使用多个嵌套作用域时会发生什么?

use*_*695 4 rust

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);
}
Run Code Online (Sandbox Code Playgroud)

这是我运行代码时得到的:

src/main.rs:11:18: 11:19 error: use of moved value: `n` [E0382]
src/main.rs:11      println!("{}", n);
                               ^
Run Code Online (Sandbox Code Playgroud)

但变量k的范围尚未结束吗?为什么不将所有权归还给变量n

Vla*_*eev 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);
}
Run Code Online (Sandbox Code Playgroud)

这样编译器知道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);
}
Run Code Online (Sandbox Code Playgroud)

看来,如果编译器知道目标类型是可变引用,它将重新借用原始引用,否则,即,如果目标类型是未知的(例如,在通用上下文中或在没有显式类型注释的情况下分配给绑定时) ,引用被移动,而不是重新借用.所以是的,围绕可变引用的行为可能会有些混乱.