How to disantangle the lifetime of the return value from the lifetime of the temporary reference?

I'm trying to create a convenient trait method, but the way Rust resolves lifetime gets in the way.

Playground

pub trait Direct<'a> {
    fn iter(&self) -> impl Iterator<Item = &'a str> + 'a;
}

pub trait Indirect<'a> {
    type Direct: self::Direct<'a>;
    fn get(&self, id: u64) -> Self::Direct;

    fn iter(&self, id: u64) -> impl Iterator<Item = &'a str> + 'a
    where
        Self: 'a,
    {
        self.get(id).iter()
    }
}

The return value of Direct::iter should not depends on the temporary lifetime of &self, right? Yet, somehow, Rust deduces that self.get(id).iter() is illegal because the return value depends on self.get(id). I could solve this by changing Direct::iter to take ownership, but that would also mean that instances of Direct cannot be reused (because its ownership has been transferred to Direct::iter).

Is there a way to solve this?

I think this may need precise lifetime capturing rules, which aren't implemented for traits yet.

2 Likes

You create a new instance of Self::Direct by calling self.get(id) in your method and then try to return something that references this instance. This doesn't work because the value local to your method gets dropped when the method returns. If you could return a reference to a local value of a method, it would be dangling immediately.

Until we get precise capturing in traits, you can use associated types.

This means you have to give the types names, which may leak implementation details you wish it didn't, and may require type erasure (e.g. Box<dyn Iterator<Item = ...>>) in cases that involve unnameable types such as closures.

Side note, you probably don't need the + 'as.

I tried to get this to work, but I guess it puts the burden of proof on the wrong party or something.[1] It might be possible with more indirection, but it'd probably be pretty hacky in any case.


  1. Which seems sort of useless to me, so maybe this could be improved in the future. ↩ī¸Ž

1 Like