How to define lifetimes on a Fn trait bound returning references?

巧了我就是萌 提交于 2020-02-05 04:34:29

问题


I'm trying to create a struct with a field, generic over F where F implements something like: Fn(&mut Compiler, &[Token]) -> &Token. The only issue is, I'm not sure how I define lifetimes on the Fn trait which satisfy the constraint that the returned &Token references data in the &[Token] slice supplied as an argument. Everything I've tried has thrown cryptic errors thus far.

Here is an MVCE which demonstrates the code (without any lifetimes):

struct Compiler;
#[derive(Debug)]
struct Token(usize);

impl Compiler {
    // missing lifetime paramters here
    fn meth(&mut self, tokens: &[Token]) -> &Token {
        tokens.get(0).unwrap()
    }
}

// missing lifetime paramters here    
struct Rule<F> where F: Fn(&mut Compiler, &[Token]) -> &Token {
    func: F
}

fn main() {
    let mut c = Compiler;
    let tokens = vec![Token(0), Token(1), Token(2)];
    let r = Rule { func: Compiler::meth };
    (r.func)(&mut c, &tokens);
}

Naturally this fails to compile with the error:

   Compiling playground v0.0.1 (/playground)
error[E0106]: missing lifetime specifier
  --> src/main.rs:11:56
   |
11 | struct Rule<F> where F: Fn(&mut Compiler, &[Token]) -> &Token {
   |                                                        ^ expected lifetime parameter
   |
   = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2

I've attempted to add lifetimes specifiers here and there, moving things around but nothing seems to work. I would really appreciate any insight into the issue. Thanks!


回答1:


As per @Stargateur's comment, the solution was to add a Higher-Ranked Trait Bound to the Fn trait declaration. The where for clause is a piece of syntax completely specific to this use case.

Normal lifetime bounds don't work, because we don't know what lifetimes will be applied to the function's arguments until call time.

So we go from this:

struct Rule<F> where F: Fn(&mut Compiler, &[Token]) -> &Token {
    func: F
}

To this:

struct Rule<F> where for<'a> F: Fn(&mut Compiler, &'a[Token]) -> &'a Token {
    func: F
}

Which dictates that the trait bounds applied to function F must satisfy all potential lifetimes of 'a at call time. Magic!



来源:https://stackoverflow.com/questions/53566761/how-to-define-lifetimes-on-a-fn-trait-bound-returning-references

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!