Destructor of trait object

I found an example of a lifetime error that I previously recorded, and the code below is it:

fn main() {
    struct Foo<'a> {
        func: Box<dyn Fn(&'a Foo) + 'a>, 
    }

    impl<'a> Foo<'a> {
        fn new() -> Self {
            Self {
                func: Box::new(|_| {}),
            }
        }

        fn run(&'a self) {}
    }
    
    let foo = Foo::new();
    foo.run();
}

What puzzled me is that when defining run is normally, but when calling foo.run(), it seems that the lifetime of foo is too short. I haven't figured out why the destructor causes a lifetie error. Thank you for your reply!

As always, it's variance.

dyn Trait<T> is invariant in T, so dyn Fn(&'a T) is invariant in &'a T, so it's invariant in 'a. That means you end up creating a &'a dyn Trait<'a>, effectively borrowing the trait object for the rest of its lifetime. That means it will be impossible to move or destroy it.

You should almost always avoid &'a (mut) T<'a>, and the explicit lifetime parameter in &'a self is the first sign that you are doing something wrong.

Similar to anti-pattern ?

Yes, &'a Invariant<'a> is an anti-pattern.

2 Likes

Thanks!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.