无法从共享引用后面的`*foo`中移出,出现了解包Option类型的错误。

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

unwrap Option type got error : cannot move out of `*foo` which is behind a shared reference

问题

如果我们有以下的代码:
```rust
struct Config {
    username: Option<String>,
    password: Option<String>,
}

fn some_fn(config: Config) {
    let foo: &Option<String> = &config.username;
    let bar: Option<&String> = config.username.as_ref();
    let name1 = foo.unwrap(); // 错误
    let name2 = bar.unwrap(); // 没有错误
}

我收到了错误信息:

error[E0507]: 无法移出位于共享引用后面的 `*foo`
   --&gt; src\main.rs:9:17
    |
9   |     let name1 = foo.unwrap();
    |                 ^^^^--------
    |                 |   |
    |                 |   由于此方法调用而移动了 `*foo`
    |                 帮助: 考虑调用 `.as_ref()` 或 `.as_mut()` 以借用类型的内容
    |                 移动发生是因为 `*foo` 具有类型 `Option<String>`,它没有实现 `Copy` 特质
    |
note: `Option::<T>::unwrap` 获取接收者 `self` 的所有权,这会移动 `*foo`

我查看了 unwrap 方法,它是这样的:

    pub const fn unwrap(self) -> T {
        match self {
            Some(val) => val,
            None => panic("called `Option::unwrap()` on a `None` value"),
        }
    }

实际上我不知道"something is behind a shared reference" 究竟意味着什么。乍一看,我以为 unwrap 接受一个 self 参数,但 foo 的类型是 &Option<String>,它是一个引用,所以错误是有道理的。但是如果我将 bar 的类型改为引用,就像这样:

    let bar: &Option<&String> = &config.username.as_ref();
    let name2 = bar.unwrap(); // 我以为这次应该会有错误,但仍然没有错误

所以回到问题,关键的区别在于 &Option<String>&Option<&String> 之间,我只是不知道错误信息 " *foo moved due to this method call" 的含义,为什么 *foo 不能移动到 unwrap 中?

这个问题的真正原因是什么?


<details>
<summary>英文:</summary>

if we have the code below:
```rust
struct Config {
    username: Option&lt;String&gt;,
    password: Option&lt;String&gt;,
}

fn some_fn(config: Config) {
    let foo: &amp;Option&lt;String&gt; = &amp;config.username;
    let bar: Option&lt;&amp;String&gt; = config.username.as_ref();
    let name1 = foo.unwrap(); // error
    let name2 = bar.unwrap(); // no error
}

I got error:

error[E0507]: cannot move out of `*foo` which is behind a shared reference
   --&gt; src\main.rs:9:17
    |
9   |     let name1 = foo.unwrap();
    |                 ^^^^--------
    |                 |   |
    |                 |   `*foo` moved due to this method call
    |                 help: consider calling `.as_ref()` or `.as_mut()` to borrow the type&#39;s contents
    |                 move occurs because `*foo` has type `Option&lt;String&gt;`, which does not implement the `Copy` trait
    |
note: `Option::&lt;T&gt;::unwrap` takes ownership of the receiver `self`, which moves `*foo`

and I look into the unwrap method, it is something like this:

    pub const fn unwrap(self) -&gt; T {
        match self {
            Some(val) =&gt; val,
            None =&gt; panic(&quot;called `Option::unwrap()` on a `None` value&quot;),
        }
    }

Actually I don't know what does "something is behind a shared reference" really means. at first glance I was thinking, unwrap takes a self param, but the foo got a type of &amp;Option&lt;String&gt;, it is a reference, so error make sense. but if I change the type of bar to a reference, like this:

    let bar: &amp;Option&lt;&amp;String&gt; = &amp;config.username.as_ref();
    let name2 = bar.unwrap(); // I thought this time there should be a error while still no error 

so get back to the issue, the key difference is between &amp;Option&lt;String&gt; and &amp;Option&lt;&amp;String&gt;, I just don't know what does the error means,"*foo moved due to this method call", why *foo can't move into unwrap?

what is REALLY cause of this issue?

答案1

得分: 2

Actually I don't know what does "something is behind a shared reference" really means.

实际上,我不知道“某物在共享引用后面”真正意味着什么。

That it's inside of / behind an & (a shared reference).

这意味着它在 &(一个共享引用)之内/之后。

at first glance I was thinking, unwrap takes a self param, but the foo got a type of &Option, it is a reference, so error make sense.

乍一看,我以为 unwrap 接受一个 self 参数,但 foo 的类型是 &Option,它是一个引用,所以错误是有道理的。

That's exactly the cause of the issue. unwrap takes the Option by value, you're trying to call it on a reference, so it tries to call the method on *foo (in order to get an owned value), which is not valid: a String is not Copy, so a Option<String> is not Copy either, therefore *foo needs to move the value, and it's not possible to move a value out of a shared reference.

这正是问题的原因。unwrap 以值的方式获取 Option,而你尝试在引用上调用它,因此它试图在 *foo 上调用该方法(以获取拥有的值),这是无效的:String 不是 Copy,所以 Option<String> 也不是 Copy,因此 *foo 需要移动该值,但不可能从共享引用中移动值。

The second case works because bar is an &Option<&T>, and a reference is always Copy, which also makes the option Copy, so *bar is valid. Hence unwrap compiles just fine.

第二种情况有效,因为 bar 是一个 &Option<&T>,引用始终是 Copy,这也使选项变为 Copy,因此 *bar 是有效的。因此,unwrap 编译得很好。

You can see it by just dereferencing, no need to even involve unwrap:

你可以通过简单地取消引用来看到它,甚至不需要涉及 unwrap

fn main() {
    let foo: &Option<String> = &None;
    let bar: &Option<&String> = &None;
    
    // *foo;  // cannot move out of `*foo` which is behind a shared reference
    *bar;
}
英文:

> Actually I don't know what does "something is behind a shared reference" really means.

That it's inside of / behind an &amp; (a shared reference).

> at first glance I was thinking, unwrap takes a self param, but the foo got a type of &Option<String>, it is a reference, so error make sense.

That's exactly the cause of the issue. unwrap takes the Option by value, you're trying to call it on a reference, so it tries to call the method on *foo (in order to get an owned value), which is not valid: a String is not Copy, so a Option&lt;String&gt; is not Copy either, therefore *foo needs to move the value, and it's not possible to move a value out of a shared reference.

The second case works because bar is an &amp;Option&lt;&amp;T&gt;, and a reference is always Copy, which also makes the option Copy, so *bar is valid. Hence unwrap compiles just fine.

You can see it by just dereferencing, no need to even involve unwrap:

fn main() {
    let foo: &amp;Option&lt;String&gt; = &amp;None;
    let bar: &amp;Option&lt;&amp;String&gt; = &amp;None;
    
    // *foo;  // cannot move out of `*foo` which is behind a shared reference
    *bar;
}

huangapple
  • 本文由 发表于 2023年7月10日 14:24:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/76651123.html
匿名

发表评论

匿名网友

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

确定