2016-03-20 17 views
3

錆の初心者なので、私はおそらくやや単純にこれを開始しました:コンパイルしようとしたとき、で迎えた私の性格に生涯のパラメータが必要なのはなぜですか?

... 

pub trait Decode<T> { 
    fn decode_from<R: io::Read + ?Sized>(&mut self, stream: &mut R) -> T; 
} 

pub struct MQTTFrame<'a> { 
    pub payload: &'a Vec<u8>, 
} 

pub struct MQTTFrameDecoder<'a> { 
    pub payload: &'a mut Vec<u8>, 
} 

impl<'a> Decode<MQTTFrame<'a>> for MQTTFrameDecoder<'a> { 
    fn decode_from<R: io::Read + ?Sized>(&mut self, stream: &mut R) -> MQTTFrame<'a> { 
     stream.read(&mut self.payload); 
     MQTTFrame{ payload: self.payload } 
    } 
} 

どの、:

StackOverflowの上のどこか
src/testbed/mod.rs:31:24: 31:36 error: cannot infer an appropriate lifetime for automatic coercion due to conflicting requirements [E0495] 
src/testbed/mod.rs:31   MQTTFrame{ payload: self.payload } 
                ^~~~~~~~~~~~ 
src/testbed/mod.rs:29:5: 32:6 help: consider using an explicit lifetime parameter as shown: fn decode_from<R: io::Read + ?Sized>(&'a mut self, stream: &mut R) 
-> MQTTFrame<'a> 
src/testbed/mod.rs:29  fn decode_from<R: io::Read + ?Sized>(&mut self, stream: &mut R) -> MQTTFrame<'a> { 
src/testbed/mod.rs:30   stream.read(&mut self.payload); 
src/testbed/mod.rs:31   MQTTFrame{ payload: self.payload } 
src/testbed/mod.rs:32  } 

- 申し訳ありませんが、私はどこ忘れてしまいました - 似たようなケースで誰かが(そのままのコードを省略)のようなので、寿命パラメータを追加することを提案:

pub trait Decode<'a, T> { 
    fn decode_from<R: io::Read + ?Sized>(&'a mut self, stream: &mut R) -> T; 
} 

impl<'a> Decode<'a, MQTTFrame<'a>> for MQTTFrameDecoder<'a> { 
    fn decode_from<R: io::Read + ?Sized>(&'a mut self, stream: &mut R) -> MQTTFrame<'a> { 
     stream.read(&mut self.payload); 
     MQTTFrame{ payload: self.payload } 
    } 
} 

そして驚くなかれ!それはコンパイルする。今私が理解できる場合なぜそれがコンパイルする。誰かが説明できます

  1. 元のコードはコンパイルされませんでしたか?
  2. なぜ修正コードがコンパイルされるのですか?

答えて

2

はここ()をコンパイルに失敗した減少テストケースです。

この関数は、任意の短い寿命の参照を取り、'bとし、寿命が'aになるように拡張しています。ボローチェッカーは、関数のコンパイルを聞かせすることを拒否。このため

fn main() { 
    let mut v = vec![]; 
    /* lifetime 'a */ { 
     let mut decoder = MQTTFrameDecoder{ payload: &mut v }; 
     let frame: MQTTFrame; 
     /* lifetime 'b */ { 
      frame = decoder.decode_from(); // borrows decoder just for lifetime 'b 
     } 
     // v is mutably borrowed (by decoder) and immutably borrowed (by frame) at the same time! oops! 
     decoder.payload.push(1); 
     println!("{:?}", frame.payload); 
    } 
} 

:これは、あなたが同時にmutablyとimmutably何かを借りることができますよう可変参照の問題です。

decoderへの参照に寿命が'aになるように強制すると、もはや問題はありません。コンパイラは寿命が短いリファレンスを使用することはできません。decoderを長く借用しなければならないため、コンパイラは再度借用しようとするとエラーが発生します。

これを達成するために、我々は

fn decode_from(&'a mut self) -> MQTTFrame<'a> { 
    MQTTFrame{ payload: self.payload } 
} 

を書きたい。しかし、今、我々は、エラーを取得:

<anon>:14:5: 16:6 error: method `decode_from` has an incompatible type for trait: 
expected bound lifetime parameter 'b, 
    found concrete lifetime [E0053] 

これを修正するには、我々は我々の形質があなたのことに注意して持っている必要がありますたったdecode_from特定の生涯ではなく、任意のものです。だから、

pub trait Decode<'a, T> { 
    fn decode_from(&'a mut self) -> T; 
} 

にデコードを変更し、我々は(ベビーサークルis.gd/BLStYq)上記のコードをしようとした場合、実装今

impl<'a> Decode<'a, MQTTFrame<'a>> for MQTTFrameDecoder<'a> { ... } 

に適切な変更を行い、ボローチェッカーは文句:

<anon>:28:9: 28:24 error: cannot borrow `*decoder.payload` as mutable more than once at a time [E0499] 
<anon>:28   decoder.payload.push(1); 

decoderへの参照は、関数decode_fromを呼び出すために取得されると、生涯が'aである必要があります。問題のある行をコメントアウトして、残りのサンプルをコンパイルしてください!変更可能な生存期間が延長されていないため、このコードは安全です。別に


decoderへの参照がある限りデコーダ自体として生きなければならないとして、あなたが実際にあなたがdecode_fromと呼ばれているすべてで後decoderを使用することはできません。この場合、&'a mut selfの代わりにselfを使用して表現するほうがよい場合があります。次に、シンタックスは少し洗練されています。デコーダが使用されると、再び使用することはできません。

pub trait Decode<T> { 
    fn decode_from(self) -> T; 
} 

pub struct MQTTFrame<'a> { 
    pub payload: &'a Vec<u8>, 
} 

pub struct MQTTFrameDecoder<'a> { 
    pub payload: &'a mut Vec<u8>, 
} 

impl<'a> Decode<MQTTFrame<'a>> for MQTTFrameDecoder<'a> { 
    fn decode_from(self) -> MQTTFrame<'a> { 
     MQTTFrame{ payload: self.payload } 
    } 
} 
+0

ありがとう、Djzin、私は完全に理解していませんが、この答えは真実のリングを持っています。私はそれについて考える時間が必要です。私はあなたに多くの質問であなたに戻っても驚かないでください。私がすでに持っているのは、Rustのコミュニティが「変更可能な参照」と言っているのは本当に「変更可能な値への(不変の)参照」を意味していますか? –

+0

私はあなたの推論をほぼ完全に理解していると信じて答えを受け入れました: –

+0

私はあなたの推論をほぼ完全に理解していると思うので答えを受け入れました。ベクトル 'payload'。同様に、 'MQTTFrame'への参照は同じベクトル' payload'への参照です。あなたが提示したコードは、スコープを広げることによって、変更可能で明確な不変の参照 - 'デコーダ'と 'フレーム' - が範囲内にある状況につながります。これは禁止されています。正しい? –

0

ライフタイムエリーションは非常に単純なケースでのみ機能します。これは彼らを弱くしますが、説明が簡単です(単純なケースも驚くほど一般的です)。

一般的な有効期間パラメータを取得すると、elisionは適用されなくなります。コンパイラはあなたの意図を推測することを拒否します。私はdecode_from機能についてelided the lifetimesを持っており、冗長ストリームパラメータを削除

pub trait Decode<T> { 
    fn decode_from<'b>(&'b mut self) -> T; 
} 

pub struct MQTTFrame<'a> { 
    pub payload: &'a Vec<u8>, 
} 

pub struct MQTTFrameDecoder<'a> { 
    pub payload: &'a mut Vec<u8>, 
} 

impl<'a> Decode<MQTTFrame<'a>> for MQTTFrameDecoder<'a> { 
    fn decode_from<'b>(&'b mut self) -> MQTTFrame<'a> { 
     MQTTFrame{ payload: self.payload } 
    } 
} 

注:

関連する問題