簡體   English   中英

我可以限制結構對生命的污染嗎?

[英]Can I limit the lifetime pollution from a struct?

我有一個包含一些東西的結構。 我為該結構實現了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!();}
}

我可以限制結構對生命的污染嗎?

通常,如果您在結構的任何字段中使用它們,則不能 出於非常充分的理由使它們顯式(請參閱為什么在Rust中需要顯式生存期? ),一旦有了包含包含顯式生存期的對象的結構,則必須對其進行傳播。

請注意,通常,結構的使用者不必擔心,因為具體的生存期是由編譯器強加的:

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

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

通過使用Self::Item的定義,還可以稍微減輕next實現的“噪音”。

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通過引用返回項目(生命周期問題)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM