Closure lifetime issue, cast requires '1 must outlive 'static

the following code snippet, when putting the decoder (a closure that uses a mutable reference of ie) into the msg_decoder, the compiler complains that: "lifetime may not live long enough: cast requires that '1 must outlive 'static".


fn test_ex16() {
    type Encoder = Box<dyn FnMut(&mut BytesMut)>;
    type Decoder = Box<dyn FnMut(&mut Bytes)>;

    pub trait IE {
        fn encode(ie: &Self, stream: &mut BytesMut)
        where
            Self: Sized;
        fn decode(stream: &mut Bytes) -> Self
        where
            Self: Sized;
        fn as_any(&self) -> &dyn Any;
    }

    pub struct MyIEa {
        num: u32,
    }

    impl IE for MyIEa {
        fn decode(stream: &mut Bytes) -> Self
        where
            Self: Sized,
        {
            MyIEa { num: 1 }
        }

        fn encode(ie: &Self, stream: &mut BytesMut)
        where
            Self: Sized,
        {
        }

        fn as_any(&self) -> &dyn Any {
            self
        }
    }

    pub struct MsgBuilder {
        pub msg_encoders: Vec<Encoder>,
        pub msg_decoders: Vec<Decoder>,
    }

    impl MsgBuilder {
        pub fn new() -> Self {
            MsgBuilder {
                msg_encoders: Vec::new(),
                msg_decoders: Vec::new(),
            }
        }

        pub fn mandatory_ie<X: IE + Clone + 'static>(&mut self, ie: &mut X) {
            let ie_cloned = ie.clone();

            // for encoder
            let encoder = move |stream: &mut BytesMut| {
                let t = ie_cloned
                    .as_any()
                    .downcast_ref::<X>()
                    .expect("mandatory_ie, T:IE != ie: &mut dyn IE");
                X::encode(t, stream);
            };
            self.msg_encoders.push(Box::new(encoder));

            // for decoder
            let decoder = |stream: &mut Bytes| {
                let ie_x = X::decode(stream);
                ie.clone_from(&ie_x);
            };

            self.msg_decoders.push(Box::new(decoder));
        }
    }
}

I tried to add lifetime parameter as follows, but it does not work.

pub fn mandatory_ie<'a: 'b, 'b, X: IE + Clone + 'static>(&'b mut self, ie: &'a mut X) {
...
}

here is the playground link:

Trait objects -- like dyn FnMut(&mut Bytes) -- always have an associated lifetime to encapsulate the validity of the erased underlying type (and it's implementation of the trait). The lifetime has various context-sensitive defaults when elided. In your type aliases, the default is 'static.

You can't create a Box<dyn FnMut(&mut Bytes) + 'static> out of a closure that captures the ie: &'some_non_static_lifetime mut X, because it's not valid after the lifetime of the &mut. You'll need to support some sort of dyn lifetime other than 'static to support this pattern.

Here's the result of adding a lifetime to the type aliases, and then following the errors to support that everywhere else.

  • MsgBuilder gained a lifetime
  • mandatory_ie uses that lifetime on the ie parameter

thanks! it really works!