Can't figure out lifetime for trait returning a closure

I have a struct and return a closure that references the data in that struct. My understanding is that the intent of the lifetime annotation is to say that the struct must outlive the closure because the closure references the struct's data. I think I've achieved that with the struct impl block, but I'm completely lost with the trait version of it:

trait ValueAt<T> {
    fn value_at(&self, t: f64) -> T;
}

struct Num {
    num: f64
}


type Func<'a> = Box<dyn Fn(f64) -> f64 + 'a>;

// No problems here
impl Num {
    fn struct_value_at<'a>(&'a self, _: f64) -> Func {
        Box::new(move |_| self.num)
    }
}

// very lost of where lifetimes should be defined
impl ValueAt<Func<'_>> for Num {
    fn value_at<'a>(&'a self, t: f64) -> Func<'a> {
        Box::new(move |_| self.num)
    }
}


fn main() {
    let n = Num{ num: 42.0 };
    println!("{}", n.struct_value_at(42.0)(42.0));
    println!("{}", n.value_at(42.0)(42.0));

}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error: `impl` item signature doesn't match `trait` item signature
  --> src/main.rs:21:5
   |
2  |     fn value_at(&self, t: f64) -> T;
   |     -------------------------------- expected fn(&Num, f64) -> std::boxed::Box<dyn std::ops::Fn(f64) -> f64>
...
21 |     fn value_at<'a>(&'a self, t: f64) -> Func<'a> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&Num, f64) -> std::boxed::Box<dyn std::ops::Fn(f64) -> f64>
   |
   = note: expected `fn(&Num, f64) -> std::boxed::Box<dyn std::ops::Fn(f64) -> f64>`
              found `fn(&Num, f64) -> std::boxed::Box<dyn std::ops::Fn(f64) -> f64>`

error: aborting due to previous error

error: could not compile `playground`.

To learn more, run the command again with --verbose.

This trait:

trait ValueAt<T> {
    fn value_at(&self, t: f64) -> T;
}

does not allow T to contain references into self.

2 Likes

As an example, here is a solution using a different trait definition that allows T to depend on the lifetime of the borrow of self:

trait ValueAt<'a, T> {
    fn value_at (self: &'a Self, t: f64)
      -> T
    ;
}

struct Num {
    num: f64
}


type Func<'a> = Box<dyn Fn(f64) -> f64 + 'a>;

// No problems here
impl Num {
    fn struct_value_at<'a> (self: &'a Self, _: f64)
      -> Func<'a>
    {
        Box::new(move |_| self.num)
    }
}

impl<'a> ValueAt<'a, Func<'a>>
    for Num
{
    fn value_at (self: &'a Self, _: f64)
      -> Func<'a>
    {
        Box::new(move |_| self.num)
    }
}
1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.