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?
jofas
January 7, 2025, 2:42pm
2
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