2017-08-14 8 views
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 

私が最初に参照r1が第2の基準r2を借りる前に隠されているので、コードをコンパイルすると予想します。明らかに、最初の借り入れはブロックの終わりまで続きますが、それは4行目以降はアクセスできなくなります。その理由は何ですか?

+0

注:現時点では借用はレキシカルですが、変更する作業があります。将来(non-Lexical Lifetimes:NLLが実装されると)rustcは 'r2'が形成されるまでに' r1'が使われないので、大丈夫です。 –

答えて

5

TL; DR:シャドウイングは名前のルックアップに関するもので、借用は寿命に関するものです。

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

言語は私たちが代わりに説明的な名前を使用することができますので、これは、人間のための非常に読みやすいではありません:ビューのコンパイラの観点から

は、変数には名前がありません。

シャドウイングは、(ここでは__1)の代わりに「オリジナル」1の再利用名称「シャドーイング」変数のレキシカルスコープのために(ここでは__2)「シャドーイング」ものに名前を解決します、上の手当あり。 シャドウ=代入

は、しかし古い1はアクセスできなくなりますという理由だけで、もはや生活をそれを意味しません!。これは、異なるスコープで特に注目すべきである:

fn main() { 
    let i = 3; 
    for i in 0..10 { 
    } 
    println!("{}", i); 
} 
常に印刷されます

3:シャドウイング変数のスコープが終了すると、名前が再び元に解決します!

+0

これはコンパイラが簡単に知ることのできる "最適化"のように思えますが、これは意味があります。 *あなたがまだ実装されていないので* – kazemakase

+0

@ kazemakase:シャドーイングとNLLは部分的にしか関連していません。 NLLsは、その名前にもかかわらず、寿命に影響するのではなく、借入国にのみ影響します。ループの例では、ループ内で 'i'がシャドーイングされているにもかかわらず、外側の' i'は引き続き使用可能です。それが借りたのであれば、借用はループ全体で活発になります。シャドーイングは純粋に*化粧*です。借り入れステータスを「変更」したい場合は、NLLが実装されたら、(1)変数に再割り当てするか、(2)それを '落とす 'ことができます。 –

2

元のようではありません。r1は、影になってから消えます。 MIRは、最後の行(r2結合)することなく、あなたのコードのために生産を検討:"shadowed"は(_3)バウンドになったとき、それは元r1は(_2)を結合することに関連し、何も変わらないこと

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 
    } 
} 

は注意。 r1という名前は変更可能な参照には適用されなくなりましたが、元の変数は依然として存在します。

私はあなたの例をシャドウイングの非常に有用なケースとは考えません。その通常の用途、例えば。ループの本体は、それを利用する可能性が非常に高い。

関連する問題