Plegeus
Plegeus

Reputation: 260

How to pass a closure to a function from a method on a struct that has a lifetime parameter in Rust?

I have a struct Foo with a lifetime parameter 'a:

struct Foo<'a> {
  /* snip */
}

I want to pass a closure (which encloses some of Foo's fields) to an arbitrary function, for example:

impl Foo<'_> {

  // ...

  pub fn do_something(&mut self) {
    self.some_object.do_something(
      Box::new(
        |a_parameter| {
          self.some_other_object.do_something_else(a_parameter);
        }
      )
    );
  }

  // ...

}

do_something would be defined something like so:

fn do_something(f: Box<dyn Fn(T)>) { /* snip */ }

The error I get is

cast requires that `'1` must outlive `'static`

Where '1 is the lifetime of the mutable reference to self in the function implemented on Foo itself.

I think the problem is that I need to specify that the closure (inside the box) lives precisely as long as the function (i.e., the scope) in which it is defined. I just don't see how to do this, I tried numerous things, e.g., adding a lifetime parameter to do_something, though, no success.

Thanks!

Edit

a (non working) example:

struct Bar {
  num: i32,
} 
impl Bar {
  fn do_something(&self, f: Box<dyn Fn(i32)>) {
    f(self.num);
  }
}

struct Foo<'a> {
  bar: &'a Bar,
  other_num: i32,
}

impl Foo<'_> {

  fn do_something(&self) {
    self.bar.do_something(
      Box::new(|n| {
        println!("{}", n + self.other_num);
      })
    );
  }

}


fn main() {
 
  let bar = Bar { num: 123, };
  let foo = Foo { bar: &bar, other_num: 456, };

  foo.do_something();

}

Upvotes: 0

Views: 145

Answers (1)

isaactfa
isaactfa

Reputation: 6651

Because you take the closure as a trait object (Box<dyn Fn(i32)>), there's an implicit + 'static bound (Box<dyn Fn(i32) + 'static>), meaning the closure isn't allowed to borrow any data. But the closure you want to pass borrows from &self. You can make the parameter more general by using an explicit lifetime:

impl Bar {
    fn do_something<'a>(&self, f: Box<dyn Fn(i32) + 'a>) {
    //             ^^^^                          ^^^^^^
    // `f` is now allowed to borrow data for any lifetime `'a`
        f(self.num);
    }
}

which can be elided

impl Bar {
    fn do_something(&self, f: Box<dyn Fn(i32) + '_>) {
        f(self.num);
    }
}

This is a really simple example. In more complex code, the lifetime requirements might be more strict than this.

Upvotes: 2

Related Questions