2017-01-01 6 views
1

なぜこれが生涯のエラーはありません。不変参照の代わりに構造体に可変参照を使用すると、生涯エラーが発生するのはなぜですか?

fn main() { 
    struct f<'a> { 
     x: &'a i32, 
    } 
    impl<'a, 'b> f<'a> { 
     fn get(&'b self) -> &'a i32 { 
      self.x 
     } 
    } 
    let x = 3; 
    let y = f { x: &x }; 
    let z = f::get(&y); 
} 

をしかし、この

fn main() { 
    struct f<'a> { 
     x: &'a mut i32, 
    } 
    impl<'a, 'b> f<'a> { 
     fn get(&'b self) -> &'a i32 { 
      self.x 
     } 
    } 
    let mut x = 3; 
    let y = f { x: &mut x }; 
    let z = f::get(&y); 
} 

は、このエラーが発生しました:

error[E0312]: lifetime of reference outlives lifetime of borrowed content... 
--> src/main.rs:7:13 
    | 
7 |    self.x 
    |    ^^^^^^ 
    | 
note: ...the reference is valid for the lifetime 'a as defined on the block at 6:36... 
--> src/main.rs:6:37 
    | 
6 |   fn get(&'b self) -> &'a i32 { 
    |         ^
note: ...but the borrowed content is only valid for the lifetime 'b as defined on the block at 6:36 
--> src/main.rs:6:37 
    | 
6 |   fn get(&'b self) -> &'a i32 { 
    |         ^
help: consider using an explicit lifetime parameter as shown: fn get(&'a self) -> &'a i32 
--> src/main.rs:6:9 
    | 
6 |   fn get(&'b self) -> &'a i32 { 
    |  ^
+0

私は正確には分かりませんが、fのxをもう変更できないので、2番目の例が失敗することが重要であると思います。 – torkleyy

+0

注: 'f'は' F'でなければならず、 'y.get()'を直接呼び出すことができます。この質問は本当に好きです! –

+0

うわー、私はしばらく時間を取ったが、私は最終的にここで何が起こっていたのか理解していると思うし、このウサギの穴を下って行くのは本当にクールだった。もう一度質問してくれてありがとう! –

答えて

2

私は最初、より慣用的なラストに再公式ます:

struct F<'a> { 
    x: &'a mut i32, 
} 

impl<'a> F<'a> { 
    fn get<'b>(&'b self) -> &'a i32 { 
     self.x 
    } 
} 

fn main() { 
    let mut x = 3; 
    let y = F { x: &mut x }; 
    let z = y.get(); 
} 

これは前と同じエラーがあります。

lifetime of reference outlives lifetime of borrowed content 

錆コンパイラはgetのこの実装を拒否しないのはなぜ?それができるので:

fn main() { 
    let mut x = 3; 

    let y = F { x: &mut x }; 
    let a = y.get(); 
    let b = y.x; 

    println!("{} {}", a, b); 
} 

はまだありませんgetをコンパイルした場合、これは大丈夫だと思う:

を以下ではgetがコンパイルされることを想定して、完全に合理的mainある

  • aは借りていませんy寿命が異なるため
  • b "consumes" y(f ROM y.x)が、我々はそう、すべては私たちが今xを指し&i32&mut i32両方を持っていることを除いて、素晴らしいです

後にそれを再利用しないでください。

注:コンパイルするにはgetunsafeを使用します。unsafe { std::mem::transmute(&*self.x) };怖い、ええ?

Aliasing XOR Mutability

錆はいつでも、あなたが何かを変更していることを保証することにより、ガベージコレクションせずにメモリ安全性を実現:ボローチェックアルゴリズムの中心に


は錆のメモリ安全性が構築される基礎となるものです観察者は、ぶら下がる可能性のあるものの内部に参照を持つことはできません。

これは、ターンでは、私たちが解釈することができます:

  • &Tエイリアシング参照として。それは一意の参照としてCopy
  • &mut Tです。一意性に違反するので、Copyではありませんが、移動することができます

この相違点はここで保存されました。

&mut Tをコピーすることができないので、&T(又は&mut T)に&mut Tから行くための唯一の方法は、再借入実行することである:間接参照の結果への参照を取ります。

これは、コンパイラによって暗黙的に行われます。幾分良好エラーメッセージのために手動でそれをやってます:

fn get<'b>(&'b self) -> &'a i32 { 
    &*self.x 
} 
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements 
--> <anon>:7:9 
    | 
7 |   &*self.x 
    |   ^^^^^^^^ 
    | 
help: consider using an explicit lifetime parameter as shown: fn get(&'a self) -> &'a i32 
--> <anon>:6:5 
    | 
6 |  fn get<'b>(&'b self) -> &'a i32 { 
    | ^

なぜそれが寿命を推測することはできませんか?再借用の生涯は'bで制限されていますが、'aが必要です。この2つの間には関係はありません。それは結果の命が(F::x経由で変更可能な参照を使用するために私達を防止する)しながら、インスタンスF借りなければならないということ。保証しますのでところで

が、これは、ここでの失態から私たちを保存しているものです

コンパイラヒントに続いて、および &'b i32作品を返す

...とは、コンパイルから上記mainを防ぐ:

impl<'a> F<'a> { 
    fn get<'b>(&'b self) -> &'b i32 { 
     &*self.x 
    } 
} 

fn main() { 
    let mut x = 3; 

    let y = F { x: &mut x }; 
    let a = y.get(); 
    let b = y.x; 

    println!("{} {}", a, b); 
} 
それは最初 mainは問題なくコンパイルできますが
error[E0505]: cannot move out of `y.x` because it is borrowed 
    --> <anon>:16:9 
    | 
15 |  let a = y.get(); 
    |    - borrow of `y` occurs here 
16 |  let b = y.x; 
    |  ^move out of `y.x` occurs here 

fn main() { 
    let mut x = 3; 

    let y = F { x: &mut x }; 
    let z = y.get(); 

    println!("{}", z); 
} 

プリント3

関連する問題