如何指定依赖于单独类型中闭包的借用绑定的生命周期?
How do I specify a lifetime that is dependent on the borrowed binding of a closure in a separate type?
我有两种类型:Lexer
和SFunction
。
SFunction
代表有状态函数,定义如下:
struct SFunction {
f: Option<Box<FnMut() -> SFunction>>,
}
重要的部分是任何 SFunction
引用一个 returns 和 SFunction
的闭包。
现在我想让这些函数通过影响相同的 Lexer
来携带状态。这意味着这些 SFunctions
中的每一个都必须具有取决于特定 Lexer
的生命周期。
如果你想更多地了解我在做什么,这里还有一些代码:
impl Lexer {
fn lex(&mut self) {
self.sfunction(Lexer::lexNormal).call()
}
fn sfunction(&mut self, f: fn(&mut Lexer) -> SFunction) -> SFunction {
SFunction::new(Box::new(|| f(self)))
// SFunction { f: Some(Box::new(move ||f(self))) }
}
fn lexNormal(&mut self) -> SFunction {
return SFunction::empty()
}
}
(Here’s a full version of the code in the Rust playground.)
如何在代码中指定此生命周期要求?
我遇到的编译器错误 "cannot infer an appropriate lifetime for capture of self
by closure due to conflicting requirements"。我很确定这里的 "conflicting requirements" 是 Box
类型假定生命周期为 'static
。我可以做类似 Box<FnMut() -> SFunction + 'a>
的事情,其中 'a
是由它所依赖的 Lexer 定义的生命周期,但我不确定如何定义这样的 'a
.
感谢您的帮助!
问题出在这一行:
SFunction::new(Box::new(|| f(self)))
此处,self
是对 Lexer
的引用,但不能保证词法分析器的寿命足够长。其实,它要活'static
一辈子!如果没有指定生命周期,boxed trait object 将使用 'static
生命周期。在代码中说,这两个声明是等价的:
<Box<FnMut() -> SFunction>>
<Box<FnMut() -> SFunction> + 'static>
并且您可以通过将代码限制为仅接受将在 'static
生命周期内存在的引用来使您的代码编译(以一种不令人满意的方式):
fn lex(&'static mut self) {
self.sfunction(Lexer::lex_normal).call()
}
fn sfunction(&'static mut self, f: fn(&mut Lexer) -> SFunction) -> SFunction {
SFunction::new(Box::new(move || f(self)))
}
当然,您是否会有 Lexer
静态生命周期是非常值得怀疑的,因为这意味着它正在对静态数据进行词法分析,这不是很有用。这意味着我们需要在您的特征对象中包含生命周期……正如您所建议的。
最终帮助发现问题的是稍微重构一下闭包:
fn sfunction(&mut self, f: fn(&mut Lexer) -> SFunction) -> SFunction {
SFunction::new(Box::new(move || {
// f(self)
let s2 = self;
let f2 = f;
f2(s2)
}))
}
编译它会产生一个错误,指向似乎是真正的问题:
<anon>:31:22: 31:26 error: cannot move out of captured outer variable in an `FnMut` closure [E0507]
<anon>:31 let s2 = self;
^~~~
<anon>:31:17: 31:19 note: attempting to move value to here
<anon>:31 let s2 = self;
^~
<anon>:31:17: 31:19 help: to prevent the move, use `ref s2` or `ref mut s2` to capture value by reference
我认为这是因为 FnMut
闭包可能会被多次调用,这意味着需要复制闭包中包含的引用,这将是个坏消息 &mut
引用应该是唯一的。
总而言之,这段代码有效:
struct SFunction<'a> {
f: Option<Box<FnOnce() -> SFunction<'a> + 'a>>,
}
impl<'a> SFunction<'a> {
fn new(f: Box<FnOnce() -> SFunction<'a> + 'a>) -> SFunction<'a> {
SFunction {
f: Some(f),
}
}
fn empty() -> SFunction<'a> {
SFunction {
f: None,
}
}
fn call(self) { }
}
struct Lexer;
impl Lexer {
fn lex(&mut self) {
self.sfunction(Lexer::lex_normal).call()
}
fn sfunction(&mut self, f: fn(&mut Lexer) -> SFunction) -> SFunction {
SFunction::new(Box::new(move || f(self)))
}
fn lex_normal<'z>(&'z mut self) -> SFunction<'z> {
SFunction::empty()
}
}
fn main() {
let mut l = Lexer;
l.lex()
}
希望我的解释是正确的,并且更改后的代码仍然适合您的用例!
我有两种类型:Lexer
和SFunction
。
SFunction
代表有状态函数,定义如下:
struct SFunction {
f: Option<Box<FnMut() -> SFunction>>,
}
重要的部分是任何 SFunction
引用一个 returns 和 SFunction
的闭包。
现在我想让这些函数通过影响相同的 Lexer
来携带状态。这意味着这些 SFunctions
中的每一个都必须具有取决于特定 Lexer
的生命周期。
如果你想更多地了解我在做什么,这里还有一些代码:
impl Lexer {
fn lex(&mut self) {
self.sfunction(Lexer::lexNormal).call()
}
fn sfunction(&mut self, f: fn(&mut Lexer) -> SFunction) -> SFunction {
SFunction::new(Box::new(|| f(self)))
// SFunction { f: Some(Box::new(move ||f(self))) }
}
fn lexNormal(&mut self) -> SFunction {
return SFunction::empty()
}
}
(Here’s a full version of the code in the Rust playground.)
如何在代码中指定此生命周期要求?
我遇到的编译器错误 "cannot infer an appropriate lifetime for capture of self
by closure due to conflicting requirements"。我很确定这里的 "conflicting requirements" 是 Box
类型假定生命周期为 'static
。我可以做类似 Box<FnMut() -> SFunction + 'a>
的事情,其中 'a
是由它所依赖的 Lexer 定义的生命周期,但我不确定如何定义这样的 'a
.
感谢您的帮助!
问题出在这一行:
SFunction::new(Box::new(|| f(self)))
此处,self
是对 Lexer
的引用,但不能保证词法分析器的寿命足够长。其实,它要活'static
一辈子!如果没有指定生命周期,boxed trait object 将使用 'static
生命周期。在代码中说,这两个声明是等价的:
<Box<FnMut() -> SFunction>>
<Box<FnMut() -> SFunction> + 'static>
并且您可以通过将代码限制为仅接受将在 'static
生命周期内存在的引用来使您的代码编译(以一种不令人满意的方式):
fn lex(&'static mut self) {
self.sfunction(Lexer::lex_normal).call()
}
fn sfunction(&'static mut self, f: fn(&mut Lexer) -> SFunction) -> SFunction {
SFunction::new(Box::new(move || f(self)))
}
当然,您是否会有 Lexer
静态生命周期是非常值得怀疑的,因为这意味着它正在对静态数据进行词法分析,这不是很有用。这意味着我们需要在您的特征对象中包含生命周期……正如您所建议的。
最终帮助发现问题的是稍微重构一下闭包:
fn sfunction(&mut self, f: fn(&mut Lexer) -> SFunction) -> SFunction {
SFunction::new(Box::new(move || {
// f(self)
let s2 = self;
let f2 = f;
f2(s2)
}))
}
编译它会产生一个错误,指向似乎是真正的问题:
<anon>:31:22: 31:26 error: cannot move out of captured outer variable in an `FnMut` closure [E0507]
<anon>:31 let s2 = self;
^~~~
<anon>:31:17: 31:19 note: attempting to move value to here
<anon>:31 let s2 = self;
^~
<anon>:31:17: 31:19 help: to prevent the move, use `ref s2` or `ref mut s2` to capture value by reference
我认为这是因为 FnMut
闭包可能会被多次调用,这意味着需要复制闭包中包含的引用,这将是个坏消息 &mut
引用应该是唯一的。
总而言之,这段代码有效:
struct SFunction<'a> {
f: Option<Box<FnOnce() -> SFunction<'a> + 'a>>,
}
impl<'a> SFunction<'a> {
fn new(f: Box<FnOnce() -> SFunction<'a> + 'a>) -> SFunction<'a> {
SFunction {
f: Some(f),
}
}
fn empty() -> SFunction<'a> {
SFunction {
f: None,
}
}
fn call(self) { }
}
struct Lexer;
impl Lexer {
fn lex(&mut self) {
self.sfunction(Lexer::lex_normal).call()
}
fn sfunction(&mut self, f: fn(&mut Lexer) -> SFunction) -> SFunction {
SFunction::new(Box::new(move || f(self)))
}
fn lex_normal<'z>(&'z mut self) -> SFunction<'z> {
SFunction::empty()
}
}
fn main() {
let mut l = Lexer;
l.lex()
}
希望我的解释是正确的,并且更改后的代码仍然适合您的用例!