2017-05-26 54 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正如我在答案的开头所述,你也需要一个明确的生命期。编译器不会自动解决该问题。 –