2017-05-26 10 views
0

私はいくつかのものを含む構造体を持っています。私はその構造体のためにIterator特性を実装し、構造体の内部データへの参照の組を返します。そのためには、少なくともいくつかのことに生涯を注釈する必要があります。私が望むのは、生涯の注釈を最小限に抑えることです。特に、元の構造体をメンバーとして持つ他の構造体については、注意が必要です。構造体から生涯汚染を制限することはできますか?

いくつかのコード:

pub struct LogReader<'a> { 
    data:String, 
    next_fn:fn(&mut LogReader)->Option<(&'a str,&'a [ConvertedValue])>, 
//... 
} 

pub struct LogstreamProcessor { 
    reader: LogReader, // doesn't work without polluting LogstreamProcessor with lifetimes 
//... 
} 

impl<'a> Iterator for LogReader<'a > { 
    type Item = (&'a str,&'a[ConvertedValue]); 

    fn next(&mut self) -> Option<(&'a str,&'a[ConvertedValue])>{(self.next_fn)(self)} 

} 

impl <'a> LogReader<'a> { 
    pub fn new(textFile:Option<bool>) -> LogReader<'a> { 
     LogReader { 
      next_fn:if textFile.unwrap_or(false) { LogReader::readNextText }else{ LogReader::readNextRaw }, 
      data: "blah".to_string() 
     } 
    } 

    fn readNextText(&mut self)->Option<(&str,&[ConvertedValue])>{unimplemented!();} 
    fn readNextRaw(&mut self)->Option<(&str,&[ConvertedValue])>{unimplemented!();} 
} 
+0

"構造体の内部データへの参照のタプルを返します。"フィールド内の関数オブジェクトではなく、メソッドを必要としませんか?今はメソッドのように 'next_fn'を使っています。 –

+0

フィールドには、オブジェクトのメソッドへのポインタが格納されます。それはいいものではありませんが、私はPythonを移植していますので、うまく翻訳できないものがたくさんあります。 –

+0

Pythonのメソッドは[methods](https://doc.rust-lang.org/book/method-syntax.html)にうまく翻訳できます。 –

答えて

1

が、私は構造体から生涯の汚染を制限することはできますか?

一般的に、あなたは構造体のフィールドのいずれかでそれらを使用している場合は、あなたができません。非常に良い理由が明示されています(Why are explicit lifetimes needed in Rust?参照)。明示的な存続期間を必要とするオブジェクトを含む構造体を取得したら、それを伝播する必要があります。

struct NameRef<'a>(&'a str); 

let name = NameRef("Jake"); // 'a is 'static 

一つは、また少しの実装に「ノイズ」を軽減できます。具体的な寿命は、コンパイラによって課されているので、通常、これは、構造体の消費者への懸念ではありません

注意nextの定義を用いて定義することができる。Self::Itemの定義を使用する。

impl<'a> Iterator for LogReader<'a > { 
    type Item = (&'a str,&'a[ConvertedValue]); 

    fn next(&mut self) -> Option<Self::Item> { 
     (self.next_fn)(self) 
    } 
} 

しかし、あなたの懸念は実際にはもっと深刻な問題を隠し:あなたが言及してきたとは異なり、nextから返される値は、必ずしも構造体からの内部データではありません。彼らは実際に生涯の生涯の間生きています'a、そしてLogReaderの中の何もその寿命によって実際に拘束されません。

これは二つのことを意味します

(1)私は完全に異なる何かを与える関数を渡すことができ、それがうまく動作します:

static NO_DATA: &[()] = &[()]; 
fn my_next_fn<'a>(reader: &mut LogReader<'a>) -> Option<(&'a str, &'a[ConvertedValue])> { 
    Some(("wat", NO_DATA)) 
} 

は(2)私は私の機能を望んでいた場合でも、ログリーダーの内部データから何かを返すには、寿命がまったく一致しないために機能しません。のは、何が起こるか見るためにとにかくそれを試してみましょう:

static DATA: &[()] = &[()]; 

fn my_next_fn<'a>(reader: &mut LogReader<'a>) -> Option<(&'a str, &'a[ConvertedValue])> { 
    Some((&reader.data[0..4], DATA)) 
} 

fn main() { 
    let mut a = LogReader { 
     data: "This is DATA!".to_owned(), 
     next_fn: my_next_fn 
    }; 

    println!("{:?}", a.next()); 
} 

コンパイラはあなたにこれを投げるでしょう:匿名の生涯#1は、ログリーダーの寿命がある

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements 
    --> src/main.rs:26:12 
    | 
26 |  Some((&reader.data[0..4], DATA)) 
    |   ^^^^^^^^^^^^^^^^^ 
    | 
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 25:88... 
    --> src/main.rs:25:89 
    | 
25 | fn my_next_fn<'a>(reader: &mut LogReader<'a>) -> Option<(&'a str, &'a[ConvertedValue])> { 
    | _________________________________________________________________________________________^ starting here... 
26 | |  Some((&reader.data[0..4], DATA)) 
27 | | } 
    | |_^ ...ending here 
note: ...so that reference does not outlive borrowed content 
    --> src/main.rs:26:12 
    | 
26 |  Some((&reader.data[0..4], DATA)) 
    |   ^^^^^^^^^^^ 
note: but, the lifetime must be valid for the lifetime 'a as defined on the body at 25:88... 
    --> src/main.rs:25:89 
    | 
25 | fn my_next_fn<'a>(reader: &mut LogReader<'a>) -> Option<(&'a str, &'a[ConvertedValue])> { 
    | _________________________________________________________________________________________^ starting here... 
26 | |  Some((&reader.data[0..4], DATA)) 
27 | | } 
    | |_^ ...ending here 
note: ...so that expression is assignable (expected std::option::Option<(&'a str, &'a [()])>, found std::option::Option<(&str, &[()])>) 
    --> src/main.rs:26:5 
    | 
26 |  Some((&reader.data[0..4], DATA)) 
    |  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

を...。 &mut LogReaderの寿命を'a&'a mut LogReader<'a>)にすると、Iteratorを実装しようとするとさらに寿命が延びることになります。これは、基本的に、'aLogReaderの値への参照と互換性がないという事実に絞り込んでいます。

これをどのように修正する必要がありますか?

それは戻り値の型が参照を持っているという事実は変わりませんので、寿命の注釈はそれは正確ではありませんが、(生涯エリジオンは、いくつかのケースで発生する可能性があるため)、それに

来ることすべての参照を返すことを避けるか、データを別のオブジェクトに委譲することで、'aをそのオブジェクトの存続期間にバインドすることができます。あなたの質問に対する答えの最後の部分はIterator returning items by reference, lifetime issueです。

+0

'通常、これは構造体のコンシューマにとっては問題ではないことに注意してください。なぜなら、コンクリートの寿命はコンパイラによって課されるからです。それは私の疑問です。LogstreamProcessorのためにはどうすればよいでしょうか。 –

+0

@CamdenNarzt答えの冒頭で述べたように、構造体にも明示的な有効期間が必要です。コンパイラは自動的にそれを解決しません。 –

関連する問題