如何指定依赖于单独类型的闭包借用绑定的生存期? [英] How do I specify a lifetime that is dependent on the borrowed binding of a closure in a separate type?

查看:50
本文介绍了如何指定依赖于单独类型的闭包借用绑定的生存期?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两种类型:LexerSFunction.

SFunction代表有状态功能,其定义如下:

SFunction stands for stateful function and is definined like so:

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

重要的部分是任何SFunction都引用一个返回SFunction的闭包.

The important part is that any SFunction references a closure that returns an SFunction.

现在,我希望这些功能通过影响相同的Lexer来实现状态.这意味着每个SFunctions的寿命必须取决于特定的Lexer.

Now I want to have these functions carry state by each affecting the same Lexer. This means that each of these SFunctions has to have a lifetime that depends on a specific Lexer.

如果想进一步了解我在做什么,这里还有更多代码:

Here's some more code if you want to get more of a sense of what I'm doing with this:

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()
    }
}

(这是Rust游乐场中的完整代码版本.)

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

How do I specify this lifetime requirement in the code?

我要说的编译器错误由于需求冲突,无法推断出通过闭合捕获self的适当时间".我很确定这里的冲突要求"是Box类型假定生存期为'static.我可以做类似Box<FnMut() -> SFunction + 'a>的操作,其中'a是它所依赖的Lexer定义的生存期,但是我不确定如何定义这样的'a.

The compiler errors I'm getting say "cannot infer an appropriate lifetime for capture of self by closure due to conflicting requirements". I'm pretty sure the "conflicting requirements" here is that a Box type assumes the lifetime to be 'static. I could do something like Box<FnMut() -> SFunction + 'a> where 'a is a lifetime defined by the Lexer it depends upon, but I'm not sure how to define such an 'a.

感谢您的帮助!

推荐答案

问题出在这一行:

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

在这里,self是对Lexer的引用,但不能保证该词法分析器将生存足够长的时间.实际上,它必须在'static生命周期内生存!如果没有指定生存期,则装箱特征对象将使用'static生存期.用代码表示,这两个声明是等效的:

Here, self is a reference to a Lexer, but there's no guarantee that the lexer will live long enough. In fact, it needs to live for the 'static lifetime! Without a lifetime specified, a boxed trait object will use the 'static lifetime. Said in code, these two declarations are equivalent:

<Box<FnMut() -> SFunction>>
<Box<FnMut() -> SFunction> + 'static>

并且可以通过限制代码只接受在'static生存期内有效的引用来使代码编译(不令人满意):

And you can make your code compile (in an unsatisfactory way) by restricting it to accept only references that will live for the 'static lifetime:

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是非常可疑的,因为那将意味着它正在对静态数据进行词法化,这不是很有用.这意味着我们需要在您的特征对象中包括生命周期……按照您的建议.

Of course, it's very doubtful that you will have a Lexer with the static lifetime, as that would mean that it's lexing static data, which wouldn't be very useful. That means we need to include lifetimes in your trait object... as you suggested.

最终,看到该问题的原因是稍微重构了闭包:

Ultimately what helped to see the problem was to restructure your closure a bit:

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)
    }))
}

对此进行编译会产生一个错误,该错误指向似乎是 real 的问题:

Compiling this produces an error that points to what seems to be the real problem:

<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引用应该是唯一的.

I believe this is because a FnMut closure may be called multiple times, which would mean that the reference enclosed in the closure would need to be copied around, which would be bad news as &mut references should be unique.

所有这些代码共同起作用:

All together, this code works:

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()
}

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

I hope my explanation is right and that the changed code still suits your use case!

这篇关于如何指定依赖于单独类型的闭包借用绑定的生存期?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆