【问题标题】:Why am I able to re-assign to a moved variable?为什么我能够重新分配给移动的变量?
【发布时间】:2020-10-14 17:13:55
【问题描述】:

我发现这段代码可以编译:

let mut s1 = String::from("hello");
let _s2 = s1;
s1 = String::from("world");
println!("{}", s1);

如果没有第三行,我会收到一个错误,抱怨不能借用移动的变量,这对我来说是可以理解的:

error[E0382]: borrow of moved value: `s1`
 --> src/main.rs:5:16
  |
2 | let mut s1 = String::from("hello");
  |     ------ move occurs because `s1` has type `std::string::String`, which does not implement the `Copy` trait
3 | let _s2 = s1;
  |           -- value moved here
4 | //s1 = String::from("world");
5 | println!("{}", s1);
  |                ^^ value borrowed here after move

第三行代码编译。

这是我的理解:s1 被移动后,s1 仍然处于某种有效状态,只是编译器阻止您访问它;如果您重新分配它,它会获得新的所有权,并且编译器会理解它并进行编译。

我说的对吗?我在哪里可以找到任何正式解释这一点的文档/规范?

【问题讨论】:

  • "移动 s1 后,s1 仍处于某种有效状态"。这表明对 Rust 的一个小误解。将用于保存的值 s1 从变量 s1 中移出后,该变量变为空。将 s1(变量)想象成一个盒子,将值想象成可以分配给这些盒子并在这些盒子之间移动的球。

标签: rust move-semantics


【解决方案1】:

s1 的原始值已被移动,因此尝试使用 s1 是非法的 - 直到它被赋予新值为止。

这是我的理解:s1 被移动后,s1 仍然处于某种有效状态,只是编译器阻止您访问它;如果您重新分配它,它会获得新的所有权,并且编译器会理解它并进行编译。

这是无效的。当 s1 被移动时,绑定现在是未初始化的内存,所以使用它是非法的。给它一个新值意味着内存不再是未初始化的,可以安全地再次使用。

与以下比较:

let mut s1; 
s1 = String::from("world");
println!("{}", s1);

在第一行,s1 与在原始代码中移动后的状态完全相同。

请注意,编译器可能会选择为第二个值使用不同的内存地址。对原始值的引用不允许在移动之后存在,因此除非您开始打印原始指针,否则此实现细节是完全不可观察的。

您可以由此推断,重新分配给已移动的可变绑定在语义上等同于引入一个新的绑定,该绑定会影响第一个绑定。这几乎是真的,但不完全是。绑定的删除顺序与引入它们的顺序相反,这里的删除顺序反映了原始绑定的顺序。

【讨论】:

  • 其实我对“有效”的含义有点困惑。我在书上看到,只有在变量超出其范围(并且它没有被转移到外部,我想)之后,它才会变得无效,对吧?
  • 当您无法保证变量实际包含的内容时,该变量无效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多