Tieing lifetimes together in a dyn Fn

I think what I'm asking is best explained with code. I want to do the following...

struct Foo {
    foo: Box<dyn for<'a> Fn(&'a Bar) -> Baz + 'a>,
}

ie. I want to store a function, with the lifetime of the output tied to the lifetime of the parameter. Is this possible?

The + 'a in dyn Fn(...) -> ... + 'a denotes the lifetime of the function (trait object), not the lifetime of the output. You need to read this as dyn Trait + 'a with Trait being Fn(...) -> ..., the + binds weaker than the ->.

In your code example, the output type Baz has no lifetimes attached at all. If the output type was, say, &Baz, then relating it to the function input type as in dyn for<'a> Fn(&'a Bar) -> &'a Baz would work perfectly well; in fact dyn Fn(&Bar) -> &Baz would even be a shorthand for this (using lifetime elision).

2 Likes

One other point of possible clarification:

If Baz is actually a struct Baz<'a> { /* ... */ }, elision works the same as with &Baz, and thus these are all the same:

dyn for<'a> Fn(&'a Bar) -> Baz
dyn for<'a> Fn(&'a Bar) -> Baz<'a>
dyn Fn(&Bar) -> Baz
dyn Fn(&Bar) -> Baz<'_>

The elision on Baz is confusing as it can lead you to think the function return doesn't borrow from the inputs [1], so Baz<'a> or Baz<'_> are recommended. [2]


  1. there is no & sigil to clue you in ↩︎

  2. You can #![warn(elided_lifetimes_in_paths)] (or deny(...)) to disallow/find them in your code. ↩︎

1 Like