A value that returns an iterator with a lifetime bounded by the lifetime of the argument
I have a trait that says that any implementation Foo
must provide a method bar
that returns an object of some type that implements Iterator<Item = u32>
:
trait Foo {
type FooIterator: Iterator<Item = u32>;
fn bar(&self) -> FooIterator;
}
In this case, I believe that the default lifelong exception means that the iterator returned bar
should live on its own, not tied to the lifetime Foo
, it iterates. Habnabit user on #rust irc suggested the following way of saying that lifetime is FooIterator
less than lifetime Foo
. that is, it allows the implementation FooIterator
to keep the reference to Foo
where it is derived from:
trait Foo<'a> {
type FooIterator: Iterator<Item = u32> + 'a;
fn bar<'b: 'a>(&'b self) -> Self::FooIterator;
}
What I really want is a case where the function bar
takes an extra argument and the implementation is FooIterator
allowed to keep a reference to both the Foo
extra argument. those. the lifetime is FooIterator
limited by the lifetime Foo
and the lifetime of the additional argument.
My literal translation of this idea would be
trait Zip {}
trait Foo<'a, 'c> {
type FooIterator: Iterator<Item = u32> + 'a + 'c;
// Foo.bar() returns an iterator that has a lifetime less than the Foo
fn bar<'b: 'a, 'd: 'c>(&'b self, &'d Zip) -> Self::FooIterator;
}
But I was told that there is no "good" way to do it. What would be the best way to implement this idiom? What would the above code do?
source to share
What you are looking for is related type constructors , a planned feature that has yet to be implemented in Rust. With associated type constructors, your code would look like this:
trait Zip {}
trait Foo {
type FooIterator<'a, 'c>: Iterator<Item = u32> + 'a + 'c;
// Foo.bar() returns an iterator that has a lifetime less than the Foo
fn bar<'a, 'b: 'a, 'c, 'd: 'c>(&'b self, &'d Zip) -> Self::FooIterator<'a, 'c>;
}
In fact, I'm not sure if all of these lifetimes are necessary because one &'a T
can be forced to &'b T
where 'a: 'b
. So the following might be good enough:
trait Zip {}
trait Foo {
type FooIterator<'a, 'c>: Iterator<Item = u32> + 'a + 'c;
// Foo.bar() returns an iterator that has a lifetime less than the Foo
fn bar<'a, 'c>(&'a self, &'c Zip) -> Self::FooIterator<'a, 'c>;
}
source to share
Depending on how you want to use this trait, you can make it work by implementing it for &'a Struct
instead Struct
, thereby "raising" the responsibility for finding the correct lifetime from that trait to the caller.
Remove the lifetime annotation from the trait and change bar
to take self
, plus another argument of the same lifetime:
trait Foo {
type FooIterator: Iterator<Item = u32>;
fn bar(self, other: Self) -> Self::FooIterator;
}
(Extracting 'a
from a trait is possible because it bar
consumes the link instead of re-markup - self
no longer need to survive the return value because it has been moved into it.)
Then impl
for the lifetime reference 'a
:
impl<'a> Foo for &'a Vec<u32> {
type FooIterator = ...; // something presumably containing 'a
fn bar(self, other: Self) -> Self::FooIterator {
...
}
}
This works because the compiler can limit the lifetime of the 'a
one for which impl is applied.
Here's a link to playgrounds where it bar
is basically a wrapper around .chain()
.
I ignore the trait Zip
because how to include it depends on what it provides. Instead, I believe it bar
only takes an argument of the same type as self
. However, perhaps you can add it as well, perhaps using the same method if you need to.
source to share