Eti
Eti

Reputation: 257

How do I pass a method to a function requiring a static lifetime parameter?

How do I pass a method to a function, considering the function takes a "handler" with a static lifetime?

(The exact use case behind this is the creation of an Iron Chain in a struct).

Considering we have the following struct Chain:

struct Chain
{
    f: Box<dyn Fn()>
}

impl Chain
{
    fn new(handler: impl Fn() + 'static) -> Self
    {
        return Chain { f: Box::new(handler) };
    }

    fn invoke(&self)
    {
        (self.f)();
    }
}

When trying to create an instance of this Chain using a closure, while also passing a method in the closure...

struct MyStruct
{
    the_answer: u32
}

impl MyStruct
{
    pub fn run(&self)
    {
        let closure = || {
            println!("Closure called");
            self.printer_method(String::from("printer_method")); // <-- Problematic line
        };

        let chain = Chain::new(closure);

        chain.invoke();
    }

    fn printer_method(&self, msg: String)
    {
        // Access to self.the_answer
        println!("The answer is {}, your message is: {}", self.the_answer, msg);
    }
}

...the compiler gives the following error:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements

I've played with the idea of declaring MyStruct and its members static, but being able to create multiple independent instances of the struct is a requirement (cf. multiple instances of an Iron web server).

Here's a Playground link.

Upvotes: 0

Views: 304

Answers (1)

rogday
rogday

Reputation: 136

In your closure:

let closure = || {
    println!("Closure called");
    self.printer_method(String::from("printer_method")); // <-- here
};

You are capturing &MyStruct because of a method call. Since closures in rust are basically just structs with "call" method, this closure can't be 'static because it would outlive the reference to MyStruct. The solution is to get generic over this lifetime:

struct Chain<'a>
{
    f: Box<dyn Fn() +'a>
}

impl<'a> Chain<'a>
{
    fn new(handler: impl Fn() + 'a) -> Self
    {
        return Chain { f: Box::new(handler) };
    }

    fn invoke(&self)
    {
        (self.f)();
    }
}

Upvotes: 2

Related Questions