Ref 'cannot infer an appropriate lifetime due to conflicting requirements' problem

I have some advice for you, don't annotate lifetimes until the compiler complains about it.

also in maybe_get_a_thing, it can be written as

fn maybe_get_thing(&self) -> Option<&Thing> {
    self.maybe_thing.as_ref()
}

here is a working version, I will explain it here

I removed the commented out stuff for brevity here

pub trait GetThingT<Thing: ?Sized> {
    fn get_thing(&self) -> &Thing;
}

pub struct HasThing<Thing> {
    pub thing: Thing,
}

impl<Thing> GetThingT<Thing> for HasThing<Thing> {
    fn get_thing(&self) -> &Thing {
        &self.thing
    }
}

pub struct Wrapper<'a, Obj: ?Sized + 'a> {
    pub inner: &'a Obj
}


impl<'a, Obj: 'a> Wrapper<'a, HasThing<Obj>> {
    pub fn compiles(&self) -> Wrapper<'a, HasThing<Obj>> {
        Wrapper {
            inner: self.inner
        }
    }

    pub fn also_compiles(&self) -> &'a dyn GetThingT<Obj> {
        let t: &dyn GetThingT<Obj> = self.inner;
        t
    }

    pub fn does_not_compile(&self) -> Wrapper<'a, dyn GetThingT<Obj>> {
        let t: &dyn GetThingT<Obj> = self.inner;
        Wrapper {
            inner: t,
        }
    }
}

First with the GetThingT trait, the function get_thing now works for all lifetimes of self, and you don't need to annotate lifetimes, which is tedious and very easy to get wrong. The desugaring after lifetime elison is

    fn get_thing<'a>(&'a self) -> &'a Thing;

lifetime elsion rules: Lifetime Elision - The Rustonomicon

HasAThing has not changed.

The impl gets simplified due to changes in GetThingT.

Wrapper has a new bound. Obj must now outlive lifetime 'a. This is there because the default, that Obj must outlive 'static, is too restrictive.

The impl block changed to reflect the change to Wrapper.
The first functions didn't change much, beyond removing annotated lifetimes and using the more explicit dyn syntax.

Overall this program has changed quite a bit. So a few things to note:

  • Lifetime elision is your friend
  • It is usually a bad idea to put references in structs, avoid it if you can
    • If you need to put references in structs, make sure that what they refer to outlives their lifetime, this will ensure that you get the more useful lifetime when you use it elsewhere
    • 'static is usually not what you want, so annotate these lifetimes
  • If you need to annotate lifetimes, try and annotate as little as possible. The Rust compiler is very good at inferring lifetimes.
    • Use lifetimes to tell where some data came from for example
fn two_refs(string: &str, slice: &[u8]) -> (&[u8], &str) {
    (&slice[1..], string)
}

This function has too many lifetimes in play, so the Rust compiler doesn't know how you want to link them up.
To help the compiler we can specify where each return value came from.

fn two_refs<'a, 'b>(string: &'a str, slice: &'b [u8]) -> (&'b [u8], &'a str) {
    (&slice[1..], string)
}

Also whenever you see a lifetime constraints i.e. 'b: 'a or T: 'a read this as lifetime 'b/type T outlives lifetime 'a, this should help you understand lifetimes better.

2 Likes