I am having trouble with lifetime bounds in the following code.
There is a Space type with an Element associated type and a function do_stuff that takes an IntoIterator of element references. I am trying to implement a generic OptionSpace whose elements are Option<S::Element> for S: Space.
In the implementation for OptionSpace<S>::do_stuff, the compiler complains that it wants S::Element: 'a in order to guarantee that Option<S::Element>: 'a even though I have bounded Self::Element: 'a and Self::Element = Option<S::Element>. If I change the bounds to S::Element: 'a then the method interface is different, which is also an error.
pub trait Space {
type Element;
fn do_stuff<'a, I>(&self, elements: I)
where
I: IntoIterator<Item = &'a Self::Element>,
Self::Element: 'a;
}
pub struct OptionSpace<S> {
pub inner: S,
}
impl<S: Space> Space for OptionSpace<S> {
type Element = Option<<S as Space>::Element>;
// type Element = Vec<<S as Space>::Element>; // Also fails
// type Element = <S as Space>::Element; // Works
fn do_stuff<'a, I>(&self, _elements: I)
where
I: IntoIterator<Item = &'a Self::Element>,
Self::Element: 'a,
// <Self as Space>::Element: 'a, // same error
// Option<<S as Space>::Element>: 'a, // same error
{
}
}
This results in
error[E0309]: the associated type `<S as Space>::Element` may not live long enough
--> src/main.rs:21:25
|
21 | I: IntoIterator<Item = &'a Self::Element>,
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `<S as Space>::Element: 'a`...
= note: ...so that the reference type `&'a Option<<S as Space>::Element>` does not outlive the data it points at
I get that S::Element might not live for 'a at the impl-level but since Self::Element: 'a is part of the bound on do_stuff shouldn't that just mean that do_stuff won't be available?
Some things that I have tried
- (Fails, interface mismatch) Replacing / adding the suggested
<S as Space>::Element: 'abound. - (Fails, same lifetime error) Use
Element = Vec<S::Element>instead ofOption<...>. - (Works) Use
Element = S::Elementinstead ofOption<...>. - (Works) Taking a single
&'a Self::Elementas an argument instead of an iterator - (Works) Use a concrete inner type instead of generic
S, e.g.Element = Option<i64>
// This works fine
pub struct OptionIntSpace;
impl Space for OptionIntSpace {
type Element = Option<i64>;
fn do_stuff<'a, I>(&self, _elements: I)
where
I: IntoIterator<Item = &'a Self::Element>,
Self::Element: 'a {}
}
Is anyone able to help me understand what is going wrong or how I can get it to work?
If it is the case that the lifetime bounds on Space::do_stuff should be expressed differently, it might be helpful to know that in my actual code do_stuff returns a value but that value does not depend on 'a.
Thanks for taking the time to read this!