英文:
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`
--> 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<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(); // error
let name2 = bar.unwrap(); // no error
}
I got error:
error[E0507]: cannot move out of `*foo` which is behind a shared reference
--> 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's contents
| move occurs because `*foo` has type `Option<String>`, which does not implement the `Copy` trait
|
note: `Option::<T>::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) -> T {
match self {
Some(val) => val,
None => panic("called `Option::unwrap()` on a `None` value"),
}
}
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 &Option<String>
, it is a reference, so error make sense. but if I change the type of bar to a reference, like this:
let bar: &Option<&String> = &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 &Option<String>
and &Option<&String>
, 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 &
(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<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.
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.
You can see it by just dereferencing, no need to even involve 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;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论