2016-09-06 12 views
6

次のコードで問題が何であるか誰にでも伝えられますか?コンパイラは寿命について不平を言っていますが、エラーメッセージはまったく意味がありません。私は考えることができるすべてを試しましたが、何も助けてくれないようです。Rustの特性オブジェクトの寿命との混同エラー

use std::borrow::BorrowMut; 

trait Trait<'a> { 
    fn accept(&mut self, &'a u8); 
} 

struct Impl<'a>{ 
    myref: Option<&'a u8>, 
} 
impl<'a> Trait<'a> for Impl<'a> { 
    fn accept(&mut self, inp: &'a u8) { self.myref = Some(inp); } 
} 

fn new<'a>() -> Box<Trait<'a> + 'a> { 
    Box::new(Impl{myref: None}) 
} 

fn user<'a>(obj: &mut Trait<'a>) {} 

fn parent<'a>(x: &'a u8) { 
    let mut pool = new(); 
    user(pool.borrow_mut()); 
} 

コンパイラエラーは全く意味がありません

error: `pool` does not live long enough 
    --> src/wtf.rs:22:10 
    | 
22 |  user(pool.borrow_mut()); 
    |   ^^^^ does not live long enough 
23 | } 
    | - borrowed value dropped before borrower 
    | 
    = note: values in a scope are dropped in the opposite order they are created 

です。借り手の残高はどうですか?私は借りた価値を使っていません!エラーメッセージへのよりがあることを

答えて

10

[OK]を、このは意味が作るんが、それが原因生涯エリジオンに見るのは難しいです。だから、ここですべての寿命は明示的に書かれたであなたのコードだと、無関係な詳細をカリング:

use std::borrow::BorrowMut; 

trait Trait<'a> {} 

struct Impl<'a> { 
    myref: Option<&'a u8>, 
} 

impl<'a> Trait<'a> for Impl<'a> {} 

fn new<'a>() -> Box<Trait<'a> + 'a> { 
    Box::new(Impl { myref: None }) 
} 

fn user<'a, 'b>(obj: &'b mut (Trait<'a> + 'b)) {} 

fn parent() { 
/* 'i: */ let mut pool/*: Box<Trait<'x> + 'x>*/ = new(); 
/* 'j: */ let pool_ref/*: &'i mut Box<Trait<'x> + 'x>*/ = &mut pool; 
      /* BorrowMut<T>::borrow_mut<'d>(&'d mut Self) -> &'d mut T */ 
/* 'k: */ let pool_borrow/*: &'i mut (Trait<'x> + 'x)*/ = Box::borrow_mut(pool_ref); 
      user(pool_borrow); 
} 

さて、parentの最後の行の観点から、私たちはただ読むことで、以下の等価性をうまくすることができますparentuserの定義と我々が持っている寿命を代入:

  • 'a = 'x
  • 'b = 'i
  • 'b = 'x

さらに、これは私たちがそれを結論することができます:

  • 'x = 'i

これが問題です。 userを定義した方法のため、pool_refの借用期間(借りているpoolの保存場所の生涯に等しい)の生涯が生涯と同じである必要がありますがに格納されており、poolに格納されている。

Boxは、それが存在する前に自分自身へのポインタを持つことができますが、それは意味をなさないです。

いずれにせよ、修正は簡単です。実際に正しい型を持っているuserを変更します。

fn user<'a, 'b>(obj: &'b mut (Trait<'a> + 'a)) {} 

これはnewによって生成型と一致します。それは "再借入" であるため、この作品

user(&mut *pool) 

:別の方法として、はちょうどborrow_mutを使用しないでください。 borrow_mutを呼び出すと、生涯が多かれ少なかれ直接変換されますが、再借用によって、コンパイラは借用をより短い期間に絞り込むことができます。別の言い方をすると、明示的にborrow_mutを呼び出すことで、コンパイラはすべての行を整列させるために生涯を "見せかけ"くらい自由にすることができません。になります。余談速いよう

私も借り値を使用していませんよ!

無関係。錆はタイプと寿命のチェック完全にをチェックします。 決しては、それが何をしているのかを見るために別の関数の本体を調べます。インターフェイスだけで動作します。コンパイラは、あなたが何をしているのかを何もチェックしたり気にかけたりしません。内にはという別の機能があります。

+0

''b = 'x'の制限はどこから来ますか? – Antimony

+0

申し訳ありませんが、私は誤って例+の固定バージョンを貼り付けました!明確にするために、 '& 'i mut(Trait <'x> +' x)'(引数)は '& 'b mut(Trait <'a> +' b)'(固定される前に 'user'の署名)で統一されています。これは、 '' b''が '' i''と '' x''の両方で統一されていることを意味します。 –

+0

ああ、意味がある!私はおそらく、新しいものはおそらくTrait <'a> + 'bのようなものを返すべきだと思うが、コンパイラはそこに+ aがないと不平を言った。 – Antimony

4

注:

error: `pool` does not live long enough 
    --> src/main.rs:25:10 
    |> 
25 |>  user(pool.borrow_mut()); 
    |>   ^^^^ 
note: reference must be valid for the block at 23:25... 
    --> src/main.rs:23:26 
    |> 
23 |> fn parent<'a>(x: &'a u8) { 
    |>      ^
note: ...but borrowed value is only valid for the block suffix following statement 0 at 24:25 
    --> src/main.rs:24:26 
    |> 
24 |>  let mut pool = new(); 
    |>      ^

のはuserを見てみましょう:

fn user<'a>(obj: &mut Trait<'a>) {} 

これは、形質に(名前の寿命の)変更可能な参照を受け入れることを言います生涯'aでパラメータ化されたオブジェクト。

newに目を向けると、私はこの方法は非常に疑わしいだと思います:

fn new<'a>() -> Box<Trait<'a> + 'a> { 
    Box::new(Impl { myref: None }) 
} 

これは、それが呼び出し側がを指定するものは何でも寿命と箱入り形質オブジェクトを返すことを言います。 That basically never makes sense

すべては、コードがborrow_mutを使用する理由を明確にしていません。私はより直接的と書いているだろう:

user(&mut *pool); 

これはTraitを取得するためにBox<Trait>を逆参照し、コンパイルされ、&mut Traitを得、変更可能な参照を取ります。

現在のところ、なぜBorrowMutの動作が異なるのか説明できません。

+0

この場合、どのように正しい生涯を新しいものにするのですか?私は、コンパイラが自動的に正しいものを選択すると仮定しました。私が明示的な生涯を渡そうとすると、それは生涯のパラメータをあまりにも多く渡すことについてのエラーを与えます。 P.S.私は、私が見た完全なエラーメッセージを投稿しました。なぜコンパイラが長いエラーメッセージを出すのかよく分かりません。 – Antimony

+0

@Antimonyあなたは1つを渡すことはありません。それは常にコードから推定されます。この場合、メソッドは 'fn new() - > Box + 'static>'(これはおそらく 'fn new()と同じです。 ) - >ボックス ')。 – Shepmaster

+0

しかし、返されたオブジェクトは実際に静的な存続期間を持たないため、意味をなさない。それとも、後で暗黙的に絞り込まれるのでしょうか? – Antimony

2

私は確信していませんなぜこのエラーが発生しますが、私は解決策を与えることができます!

まず、borrow_mutを使用すると、返される参照の有効期間が不必要に制限されるようです。参照を作成するために演算子を使用すると、エラーが解決されます。我々ははそれをしない場合

fn parent() { 
    let mut pool = new(); 
    user(&mut *pool); 
} 

しかし、我々はuserobj引数にTraitオブジェクトにバインドされた有効期間を追加することで、エラーを解決することができます。

fn user<'a>(obj: &mut (Trait<'a> + 'a)) {}