fn main() {
let mut m = 12;
{
let n = &mut m;
*n = 13;
{
let k = n;
*k = 20;
println!("{}", k);
} // k's scope ends here, right?
println!("{}", n);
}
println!("{}", m);
}
这是我运行代码时得到的结果:
src/main.rs:11:18: 11:19 error: use of moved value: `n` [E0382]
src/main.rs:11 println!("{}", n);
^
但变量k
尚未结束其范围?为什么不将所有权归还给变量n
?
答案 0 :(得分:8)
但变量k是否已结束其范围呢?为什么不将所有权归还给变量n?
是的,k
的范围已经结束,但为什么你认为它应该归还所有权呢?
在Rust中没有任何东西可以“归还所有权”。如果某个类型未实现Copy
(并且&mut
引用绝对不实现),则只能移动其值。移动意味着所有权转移,因此由所有权的接收者决定如何处理该值。因此,当k
超出范围时,指针实际上被“销毁”(指针本身,而不是值)。由于它已移出n
,绑定实际上变为未初始化,因此您会收到此错误。
&mut
引用 是唯一的,虽然它们不可复制,因此只能移动,有时它们会自动重新借用,即编译器会自动为您插入&mut *p
。我不记得应用自动重新借用时的确切规则(据我记得,当可变引用传递给函数时可能发生这种情况,可能还有其他地方),但这不是这种情况。为了使您的代码有效,您需要明确地重新借用该值:
fn main() {
let mut m = 12;
{
let n = &mut m;
*n = 13;
{
let k = &mut *n; // explicit referencing of the dereferenced value
*k = 20;
println!("{}", k);
}
println!("{}", n);
}
println!("{}", m);
}
这样编译器就知道n
没有移入k
,并且允许您在k
的范围结束后使用它。
正如旁注,以下(感谢Veedrac的提醒)也可以再次使用,因为自动重新生成:
fn main() {
let mut m = 12;
{
let n = &mut m;
*n = 13;
{
let k: &mut _ = n; // automatic reborrowing because of type annotation
*k = 20;
println!("{}", k);
}
println!("{}", n);
}
println!("{}", m);
}
看起来如果编译器知道目标类型是可变引用,它将重新借用原始引用,否则,即,如果目标类型是未知的(例如,在通用上下文中或在没有显式的情况下分配给绑定时)类型注释),引用被移动,而不是重新借用。所以是的,围绕可变引用的行为可能会有些混乱。