2017-05-26 72 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()); 
} 

,編譯器將拋出你:

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)) 
    |  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

...其中匿名壽命#1是日誌讀取器的壽命。強制&mut LogReader也有終身'a&'a mut LogReader<'a>)將導致嘗試實施Iterator進一步生命期問題。這基本上縮小到'a與提及LogReader本身的值不相符的事實。

那麼,我們該如何解決這個問題呢?

但這並不改變該返回類型的引用,因此壽命註解進入它

雖然這是不準確的(因爲在某些情況下會出現一輩子省音),這一事實給解決方案提示:或者避免返回引用或將數據委託給單獨的對象,以便'a可以綁定到該對象的生命週期。對你的問題的答案的最後一部分是Iterator returning items by reference, lifetime issue

+0

'請注意,通常這不是結構體的消費者關心的問題,因爲具體的生命週期是由編譯器強加的。那是我的問題,我怎麼才能讓它爲LogstreamProcessor工作。 –

+0

@CamdenNarzt正如我在答案的開頭所述,你也需要一個明確的生命期。編譯器不會自動解決該問題。 –

相關問題