What I'm trying to do is to store the inner components of a type that implements the Chunkable trait, in a Collection, and later be able to iterate over those components grouped in chunks, converted into the original type.
The last bit is what I'm struggling with. After following the compiler indications I've got to the point where I need some help understanding these lifetime issues.
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src/main.rs:64:18
|
64 | self.vec.chunks(self.chunk_size).map(|c| c.into())
| ^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the impl at 61:6...
--> src/main.rs:61:6
|
61 | impl<'a, C: Chunkable<T> + From<&'a [T]>, T: 'a + Copy> Container<C, T> {
| ^^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:64:9
|
64 | self.vec.chunks(self.chunk_size).map(|c| c.into())
| ^^^^^^^^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that return value is valid for the call
--> src/main.rs:63:42
|
63 | pub fn chunks_iter_type(&'a self) -> impl DoubleEndedIterator<Item = C> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Edit: this is the conflicting function. I'm trying to devise a way forward but I still don't understand where the problem lies exactly. The error message doesn't seem very clear to me.
You should probably put most bounds on the method itself
impl<C: Chunkable<T>, T> Container<C, T> {
// iterate over the stored components, returning the original type.
pub fn chunks_iter_type<'a>(&'a self) -> impl DoubleEndedIterator<Item = C> + 'a
where
C: From<&'a [T]>,
{
self.vec.chunks(self.chunk_size).map(|c| c.into())
}
}
This also avoids the need for T: 'a
(in the method, the compiler infers this bound implicitly due to T’s appearance in the type of the self: &'a Container<C, T> argument).
In summary, now re-reading the compiler error message, I think I understand now that what's implying is that the returned type has an implicit and conflicting static lifetime bound, and I should try to bound it to 'a.
note: but, the lifetime must be valid for the static lifetime...
note: ...so that return value is valid for the call
--> src/main.rs:63:42
|
63 | pub fn chunks_iter_type(&'a self) -> impl DoubleEndedIterator<Item = C> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
now, the impl DoubleEndedIterator<Item = &'a [T]>mentions the lifetime 'a, and this enables it to be able to capture references (or other types) with lifetime 'a as per the rules of how impl Trait in return types works.
(The link is into the RFC introducing the feature because it’s actually not really well-documented otherwise, as far as I’m aware.)
In argument position, the type fulfilling an impl Trait is free to reference any types or lifetimes whatsoever. […]
For return position, things are more nuanced.
This RFC proposes that all type parameters are considered in scope for impl Trait in return position […]. The lifetimes in scope include only those mentioned "explicitly" in a bound on the impl Trait.
Adding the + 'a helps because it (syntactically) “mentions” the lifetime 'a.
the return type is the type Map<std::slice::Chunks<'a, T>, {closure type}> where {closure type} stands for the unnameable type of the FnMut(&'a [T]) -> C closure “|c| c.into()”. This type “references/mentions” the lifetime 'a. The “types / lifetimes in scope” in the description in that RFC talks about the question which of the generic type and lifetime arguments can be referenced/mentioned in the actual return type.
I’m not sure if the type of that FnMut(&'a [T]) -> C closure itself also references/mention the lifetime 'a, it doesn’t really matter in this case anyways.
In-fact, I guess the compiler is to be smart about this 'a in Map<std::slice::Chunks<'a, T>, {closure type}> and tries to not use 'a. See, the lifetime is actually some lifetime parameter 'b from the slice::chunks(self: &'b [T], chunk_size: usize) -> Chunks<'b, T> call, so the return type is Map<std::slice::Chunks<'b, T>, {closure type}>.
Rustc notices that
this lifetime 'b cannot outlive 'a, because the argument passed to slice::chunks is a re-borrow of self: &'a Container<C, T> (and you cannot reborrow this reference for longer than 'a)
the lifetime 'b is mentioned in the return type, but that return type is not allowed to mention any lifetimes at all (besides 'static).
You've given me more than I could ever ask for. Bravo! ... In fact I'm gonna have to reread the last post several times to fully grasp it because it goes a little over my head.