首页 文章

为什么阴影不会释放借来的参考?

提问于
浏览
3

看起来阴影变量不会释放它所持有的借来的引用 . 以下代码无法编译:

fn main() {
    let mut a = 40;
    let r1 = &mut a;
    let r1 = "shadowed";
    let r2 = &mut a;
}

带有错误消息:

error[E0499]: cannot borrow `a` as mutable more than once at a time
 --> src/main.rs:5:19
  |
3 |     let r1 = &mut a;
  |                   - first mutable borrow occurs here
4 |     let r1 = "shadowed";
5 |     let r2 = &mut a;
  |                   ^ second mutable borrow occurs here
6 | }
  | - first borrow ends here

我希望代码能够编译,因为在借用第二个引用 r2 之前,第一个引用 r1 被遮蔽了 . 显然,第一次借用直到街区结束,尽管在第4行之后不再可以进入 . 为什么会这样?

2 回答

  • 5

    TL;DR: Shadowing is about name-lookup, borrowing is about lifetimes.

    从编译器的角度来看,变量没有名称:

    fn main() {
        let mut __0 = 40;
        let __1 = &mut __0;
        let __2 = "shadowed";
        let __3 = &mut __0;
    }
    

    这对于人类来说不是非常易读,因此该语言允许我们使用描述性名称 .

    阴影是重用名称的一个限制,对于"shadowing"变量的词法范围,它将名称解析为"shadowing"(此处为 __2 )而不是"original"(此处为 __1 ) .

    然而,仅仅因为旧的不能再被访问并不意味着它不再存在:暗影!=分配 . 这在不同的范围内尤其值得注意:

    fn main() {
        let i = 3;
        for i in 0..10 {
        }
        println!("{}", i);
    }
    

    将始终打印 3 :一旦阴影变量的范围结束,名称将再次解析为原始!

  • 2

    它不像原来的 r1 在被遮蔽后不再存在;考虑为您的代码生成的MIR没有最后一行( r2 绑定):

    fn main() -> () {
        let mut _0: ();                      // return pointer
        scope 1 {
            let mut _1: i32;                 // "a" in scope 1 at src/main.rs:2:9: 2:14
            scope 2 {
                let _2: &mut i32;            // "r1" in scope 2 at src/main.rs:3:9: 3:11
                scope 3 {
                    let _3: &str;            // "r1" in scope 3 at src/main.rs:4:9: 4:11
                }
            }
        }
    
        bb0: {
            StorageLive(_1);                 // scope 0 at src/main.rs:2:9: 2:14
            _1 = const 40i32;                // scope 0 at src/main.rs:2:17: 2:19
            StorageLive(_2);                 // scope 1 at src/main.rs:3:9: 3:11
            _2 = &mut _1;                    // scope 1 at src/main.rs:3:14: 3:20
            StorageLive(_3);                 // scope 2 at src/main.rs:4:9: 4:11
            _3 = const "shadowed";           // scope 2 at src/main.rs:4:14: 4:24
            _0 = ();                         // scope 3 at src/main.rs:1:11: 5:2
            StorageDead(_3);                 // scope 2 at src/main.rs:5:2: 5:2
            StorageDead(_2);                 // scope 1 at src/main.rs:5:2: 5:2
            StorageDead(_1);                 // scope 0 at src/main.rs:5:2: 5:2
            return;                          // scope 0 at src/main.rs:5:2: 5:2
        }
    }
    

    请注意,当 "shadowed" 绑定( _3 )时,它不会更改与原始 r1 绑定相关的任何内容( _2 );名称 r1 不再适用于可变引用,但原始变量仍然存在 .

    我不认为你的例子是一个非常有用的阴影案例;它的通常应用,例如循环体,更有可能利用它 .

相关问题