map函数:无法移出…,因为它位于可变引用之后。

huangapple go评论83阅读模式
英文:

map function : cannot move out of ... which is behind a mutable reference

问题

我正在按照这个教程,并遇到了关于map函数的一些有趣内容。这里是一个关于问题的玩具模型。

#[derive(Debug)]
pub struct Word(String);
pub fn main(){
    let words = "wwww";
    let mut word = Word(words.to_string());
    
    let mut o2 = Some(&word);

    let ref2 = &mut o2; 
    let new = ref2.map(|w|{
        "nnnnn"
    });

    println!("{:?}", new);
    println!("{:?}", o2);
}

输出如下所预测:

Some("nnnnn")
Some(Word("wwww"))

然而,如果我更改这一行:

let mut o2 = Some(&word);

为:

let mut o2 = Some(&mut word);

这是错误消息:

error[E0507]: cannot move out of `*ref2` which is behind a mutable reference
   --> src/main.rs:10:15
    |
10  |         let new = ref2.map(|w|{
    |  _________________^____-
    | |  _______________|
    | | |
11  | | |         "nnnnn"
12  | | |     });
    | | |      ^
    | |_|______|
    |   |      `*ref2` moved due to this method call
    |   |______help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents
    |          move occurs because `*ref2` has type `Option<&mut Word>`, which does not implement the `Copy` trait
    |
note: this function takes ownership of the receiver `self`, which moves `*ref2`
   --> /home/wh/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/option.rs:919:28
    |
919 |     pub const fn map<U, F>(self, f: F) -> Option<U>
    |            

似乎当`o2`是一个包装器的普通引用时,

```rust
o2 = Some(&word)

map函数并不会真正尝试拥有o2

但是,一旦它是一个可变引用的包装器,

o2 = Some(&mut word)

map函数突然想要拥有o2

因此,Option内部的数据类型可以影响map函数的行为,背后的原因是什么呢?

英文:

I'm following this tutorial
and came across something really interesting about the map function.
Here is a toy model of the problem.

#[derive(Debug)]
pub struct Word(String);
pub fn main(){
    let words = &quot;wwww&quot;;
    let mut word = Word(words.to_string());
    
    let mut o2 = Some(&amp;word);

    let ref2 = &amp;mut o2; 
    let new = ref2.map(|w|{
        &quot;nnnnn&quot;
    });

    println!(&quot;{:?}&quot;, new);
    println!(&quot;{:?}&quot;, o2);
}

The output is as predicted :

Some(&quot;nnnnn&quot;)
Some(Word(&quot;wwww&quot;))

However, if I change this line

let mut o2 = Some(&amp;word);

to

let mut o2 = Some(&amp;mut word);

here is the error message:

error[E0507]: cannot move out of `*ref2` which is behind a mutable reference
   --&gt; src/main.rs:10:15
    |
10  |         let new = ref2.map(|w|{
    |  _________________^____-
    | |  _______________|
    | | |
11  | | |         &quot;nnnnn&quot;
12  | | |     });
    | | |      ^
    | |_|______|
    |   |      `*ref2` moved due to this method call
    |   |______help: consider calling `.as_ref()` or `.as_mut()` to borrow the type&#39;s contents
    |          move occurs because `*ref2` has type `Option&lt;&amp;mut Word&gt;`, which does not implement the `Copy` trait
    |
note: this function takes ownership of the receiver `self`, which moves `*ref2`
   --&gt; /home/wh/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/option.rs:919:28
    |
919 |     pub const fn map&lt;U, F&gt;(self, f: F) -&gt; Option&lt;U&gt;
    |            

It seems like when o2 is a wrapper of some normal reference,

 o2 = Some(&amp;word),

the map function wouldn't really try to take ownership of o2,

But, once, it is a wrapper of some mutable reference,

 o2 = Some(&amp;mut word),

the map function suddenly wants to take ownership o2.

So the data type inside an Option could affect the behaviour of the map function,
What is the reasoning behind this?

答案1

得分: 2

让我们看一下 map 的签名:

pub fn map<U, F>(self, f: F) -> Option<U>
where
    F: FnOnce(T) -> U

在这里 selfOption<T>,这就导致了你的问题。

在语句 let mut o2 = Some(&amp;word); 中,o2 的类型是 Option<&amp;Word>。因此,当你对其调用 map 时,泛型会特化为 map(self, f: FnOnce(&amp;Word) -> &amp;str) -> Option<&amp;str>。只存在不可变引用,并且所有不可变引用都实现了 Copy

但是在语句 let mut o2 = Some(&amp;mut word); 中,o2 的类型是 Option<&amp;mut Word>,并且 map 会特化为 map(self, f: FnOnce(&amp;mut Word) -> &amp;str) -> Option<&amp;str>。可变引用没有 Copy 的实现。

据我理解,不可变引用会被复制,map 执行时就好像没发生任何特殊情况。但如果使用可变引用,就需要它的所有权,因为它无法被复制。

英文:

Let's take a look at map's signature:

pub fn map&lt;U, F&gt;(self, f: F) -&gt; Option&lt;U&gt;
where
    F: FnOnce(T) -&gt; U

Here self is Option&lt;T&gt;, which causes your problem.

In statement let mut o2 = Some(&amp;word);, the type of o2 is Option&lt;&amp;Word&gt;. Thus, when you call map on it, the generic specializes to map(self, f: FnOnce(&amp;Word) -&gt; &amp;str) -&gt; Option&lt;&amp;str&gt;. Only immutable references exist, and Copy is implemented for all immutable references.

But in statement let mut o2 = Some(&amp;mut word);, the type of o2 is Option&lt;&amp;mut Word&gt; and map specializes to map(self, f: FnOnce(&amp;mut Word) -&gt; &amp;str) -&gt; Option&lt;&amp;str&gt;. Mutable references have no Copy implementation.

To my understanding, the immutable reference is copied, and map execute as if nothing special happened. But if a mutable reference is used, its ownership is needed since it cannot be copied.

huangapple
  • 本文由 发表于 2023年7月7日 07:12:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/76633036.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定