这里有一个有效的例子。我在main中使用了一个新的stdin
句柄。我将它传递给函数parse_something。在此函数中,stdin.lock()
返回一个锁定保护,我将其存储到最终返回的结构中。想象结构是某种迭代器。而且我希望这个迭代器只要它是活的就保持stdin
锁定。到现在为止还挺好。锁定保护程序与生命周期'a
相关联。这是从main的新stdin
句柄开始的。
use std::io::BufRead;
struct SomeIterator<B: BufRead> {
buffer: B,
}
fn parse_something<'a>(stdin: &'a std::io::Stdin) -> SomeIterator<std::io::StdinLock<'a>> {
let r = SomeIterator {
buffer: stdin.lock(),
};
r
}
fn main() {
let stdin = std::io::stdin();
parse_something(&stdin);
}
现在让我们尝试在stdin
函数中移动parse_something
句柄实例化。
use std::io::BufRead;
struct SomeIterator<B: BufRead> {
buffer: B,
}
fn parse_something<'a>() -> SomeIterator<std::io::StdinLock<'a>> {
let stdin = std::io::stdin();
let r = SomeIterator {
buffer: stdin.lock(),
};
r
}
fn main() {
parse_something();
}
我收到错误error[E0597]: `stdin` does not live long enough
。到现在为止还挺好。 stdin必须和'a
一样长。为此,我应该将stdin处理程序存储在SomeIterator
。
问题是,我必须在.lock()
句柄上使用相同生命期stdin
的{{1}}。我无法弄清楚如何。
这不起作用,因为lockguard引用了'a
变量,而不是let stdin
中的(最终移动的)stdin
属性。
SomeIterator
最终,我全力以赴,并添加了一些随机的垃圾,希望也许我很幸运并且在解决方案上绊倒了。虽然没有运气。在这里,我将struct SomeIterator<B: BufRead> {
stdin: std::io::Stdin,
buffer: B,
}
fn parse_something<'a>() -> SomeIterator<std::io::StdinLock<'a>> {
let stdin = std::io::stdin();
let guard = stdin.lock();
let r = SomeIterator {
stdin: stdin,
buffer: guard,
};
r
}
放在一个方框中。从技术上讲,盒子的内容永远不应该在内存中移动。只有框“指针对象”是。我希望stdin
实际上使用Box中内容的生命周期。哪个应该是r.stdin.lock()
,因为Box是'a
的一部分,SomeIterator
本身在'a
上是通用的。
可悲的是,r.stdin.lock()
在致电r.stdin
之前实际借用.lock()
时,一切都变得糟透了。这种借用仅适用于函数的范围。 `*r.stdin` does not live long enough
点击率很高。
struct SomeIterator<'a, B: BufRead + 'a> {
stdin: Box<std::io::Stdin>,
buffer: Option<B>,
_marker: std::marker::PhantomData<&'a B>,
}
fn parse_something<'a>() -> SomeIterator<'a, std::io::StdinLock<'a>> {
let mut r = SomeIterator {
stdin: Box::new(std::io::stdin()),
buffer: None,
_marker: std::marker::PhantomData{},
};
r.buffer = Some(r.stdin.lock());
r
}
我怀疑在删除细节之后,我的问题最终变成:安全的Rust是否可以存储对兄弟属性的引用?但我可能是错的。