rust - 如何指定依赖于单独类型中闭包的借用绑定(bind)的生命周期?

标签 rust lifetime

我有两种类型:LexerSFunction .

SFunction代表有状态函数,定义如下:

struct SFunction {
    f: Option<Box<FnMut() -> SFunction>>, 
}

重要的是任何 SFunction引用一个返回 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.)

如何在代码中指定此生命周期要求?

我得到的编译器错误是“由于需求冲突,无法通过关闭推断出捕获 self 的适当生命周期”。我很确定这里的“冲突要求”是 Box type 假定生命周期为 'static .我可以做类似 Box<FnMut() -> SFunction + 'a> 的事情其中 'a是由它所依赖的 Lexer 定义的生命周期,但我不确定如何定义这样的 'a .

感谢您的帮助!

最佳答案

问题出在这一行:

SFunction::new(Box::new(|| f(self)))

这里,self 是对 Lexer 的引用,但不能保证 lexer 会存在足够长的时间。事实上,它需要在 'static 生命周期内存活!如果没有指定生命周期,盒装特征对象 将使用'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()
}

我希望我的解释是正确的,并且更改后的代码仍然适合您的用例!

关于rust - 如何指定依赖于单独类型中闭包的借用绑定(bind)的生命周期?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32879649/

相关文章:

testing - 运行 Rust 测试时如何在函数内部执行暴力函数验证?

types - 为什么索引显式类型的向量会因类型推断错误而失败?

rust - 对于具有多个生命周期参数的迭代器,impl Iterator 失败

rust - 如何防止值被 move ?

scope - 为什么泛型生命周期不符合嵌套范围的较小生命周期?

rust - 如何在 Rust 中链接返回结果的函数?

data-structures - 一个模块中的 Rc<T>s 和另一个模块中的 Rc<RefCell<T>>s 引用相同的数据

generics - 为什么我需要为不是结构成员的结构的通用参数提供生命周期?

generics - 将函数作为参数传递时,如何遵守生命周期限制?