Lifetime and closure

Hello.
I am a C# developer and I am learning rust as a hobby.
I'm trying to give a closure as the value of a field.

fn main() {
    let mut s1:Vec<String> = vec!["hello".to_string()];
    let closure =  |str:&str| {
        s1.push(str.to_string());
    };
    let boxed = Box::new(closure);
    let mut test = Test::new(boxed);
    test.world("world");
    println!("{:?}",s1);
}

pub struct Test{
    output:Box<dyn FnMut(&str)>
}
impl Test{
    pub fn new(output:Box<dyn FnMut(&str)>)->Test{
        Test { output }
    }
    pub fn world(&mut self,str:&str){
        (self.output)(str);
    }
}

And compiler complains about life time of s1 says "s1 does not live long enough"

note: due to object lifetime defaults, Box<dyn for<'a> FnMut(&'a str)> actually means Box<(dyn for<'a> FnMut(&'a str) + 'static)>

Why isn't the lifetime of s1 long enough? Isn't it the scope of s1 be until the end of the program?

Lifetime elision on trait objects is a complex topic, you can read more about it here. According to quinedot's excellent summary of the basic elision rules, Box<dyn T> always infers the trait object to be 'static:

For non-lifetime-parameter types like Box<dyn Trait>, and for bare dyn Trait, it's 'static

If you don't elide the lifetime of the trait object and drop the closure before using s1 again, your code compiles:

fn main() {
    let mut s1:Vec<String> = vec!["hello".to_string()];
    let closure =  |str:&str| {
        s1.push(str.to_string());
    };
    let boxed = Box::new(closure);
    let mut test = Test::new(boxed);
    test.world("world");
    drop(test);
    println!("{:?}",s1);
}

pub struct Test<'a> {
    output:Box<dyn FnMut(&str) + 'a>
}

impl<'a> Test<'a> {
    pub fn new(output:Box<dyn FnMut(&str) + 'a>) -> Test<'a> {
        Test { output }
    }
    pub fn world(&mut self,str:&str){
        (self.output)(str);
    }
}

Playground.

2 Likes

Thank you! that solves the problem. There's a lot to read to learn Rust...

1 Like