[英]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.