2017-05-24 10 views
0

私の質問方法を訂正してくれてありがとう。コードをコンパイル可能にするためにいくつかの改訂を行いました。`Into`ジェネリックを扱うときの寿命の問題

use std::marker::PhantomData; 

struct Brace { 
    x: i32, 
} 

impl Brace { 
    fn transform(&self, n: i32) -> Devil { 
     Devil { 
      hp: self.x + n, 
      weapon: None, 
     } 
    } 
} 

struct Bar<'a> { 
    tasty: &'a str, 
} 

struct Foo<'a, B> 
    where B: 'a + Into<Bar<'a>> 
{ 
    brace: Brace, 
    buz: Option<B>, // buz is of generic type B, and is able to be turned into bar. 
    phantom: PhantomData<&'a B>, // A marker that is used to resolve 'unused lifetime parameter a' 
} 

impl<'a, B: Into<Bar<'a>>> Foo<'a, B> { 
    fn transform_and_arm(self) { 
     // line B 
     let brace1: Brace = self.brace; 
     let mut devil: Devil = brace1.transform(12345); // line A 
     let buz = self.buz.unwrap(); 
     // Before this line, it passes the compiler. 
     // Uncommenting the following line causes compiler to argue that the brace1 at line A doesn't live long enough. It says that borrowed value must be valid for the lifetime 'a as defined on the body at line B, but the borrowed value only lives until line C. 
     // devil = devil.arm(buz); 
     // Although adding the above line fails, making the weapon directly won't cause the compiler to complain. 
     // Uncommenting the following line passes compiler. 
     // let weapon = buz.into(); 

     // The compiler stops the devil from arming itself before I even try to write the following line. 
     // devil.slay_the_world(); 
    } // line C 
} 

struct Devil<'a> { 
    hp: i32, 
    weapon: Option<Bar<'a>>, 
} 

impl<'a> Devil<'a> { 
    fn arm<B: Into<Bar<'a>>>(mut self, biu: B) -> Devil<'a> { 
     self.weapon = Some(biu.into()); 
     self 
    } 

    fn slay_the_world(self) { 
     unimplemented!() 
    } 
} 

transform_and_arm()方法はbracebuzを奪うことによってFooのインスタンスを消費するように設計されています。 brace.transform()を呼び出してbraceDevilにします。それはbuz.unwrap()と悪魔を与えることによって悪魔を強化します。

問題は、let weapon = buz.into();を呼び出すことは合法ですが、devil = devil.arm(buz);を呼び出すと生涯の問題が発生することです。

問題は生涯に関係しているようです。悪魔のためのものがなければ、これらの問題はすべて消滅するでしょう。

答えて

0

編集私の以前の回答は、問題を非常にうまく説明していませんでした。ここに別の試みがあります。

transformに欠陥があるため、この問題が発生しています。のは、コンパイラがtransformのために推論しているものを見てみましょう寿命が、理由を見つけるには:

fn transform<'a>(&'a self, n: i32) -> Devil<'a> 

私たちは、コンパイラが関数に渡されselfを基準として返さDevil同じ寿命を与えることを決めたことがわかります。

それでは、Devilを見てみましょう:

struct Devil<'a> { 
    hp: i32, 
    weapon: Option<Bar<'a>>, 
} 

我々はDevilの寿命パラメータは、そのweaponに関連していることがわかります。

...しかし、バックtransform

fn transform<'a>(&'a self, n: i32) -> Devil<'a> { 
    Devil { 
     hp: self.x + n, 
     weapon: None, 
    } 
} 

を探しています... Devilの寿命パラメータの唯一の目的ですweaponは、参照に関連しない方法であることは明らかですselfになるので、&selfDevilの寿命はとなるはずです。

これは問題につながる後、私たちは別の生涯とDevilweaponを与えたいかもしれない、と私たちはこれを実行できないようにする必要があり理由がないようDevilは、実際の武器を割り当てられたとき。

transformの現在の実装では、返されたDevilの参照がselfを超えることを禁止していますが、これはそうである必要はありません。

fn transform<'a, 'b>(&'a self, n: i32) -> Devil<'b> 
+0

ありがとうございました!それは明らか&selfと返さDevilは無関係な寿命を有することを確認するためにtransformに注釈を付け、明示的に、問題を解決するために

テストコードで同じ変更を行った後でコンパイルされ、問題の原因を理解し始めます。しかし、実際の状況は、 'transform()'がサードパーティライブラリ(実際にはhyper :: client :: Client :: get())として提供される関数であるということです。私は 'transform_and_arm(self)'がなぜうまくいかないのか不思議です。悪ふざけはC行まで生きているので、FooはC行の後に消費されるので、中途半端に残っていたり、Fooが残っているわけではありません。 –

+0

もう一つの関連する観察は、 'devil.slay_the_world();'エラーは表示されますが、 'devil.arm(buz);のコメントは解除されます。私は 'transform_and_arm(self)'でFooのすべてのフィールドを消費したいだけです。 –