Not clearly a duplicate of the linked question
This question is about returning a reference to the member of an owned struct, not about storing a reference to an owned value on the same object.
I'm hoping for some explanation, or some hints towards what is happening in the very specific case.
I'm using the streaming iterators library to build runtime pipelines where the exact types of iterators are not known at compile time. For example, I want to construct a pipeline like
read a file > gunzip it > parse the contents > extract fields
To do this efficiently, borrowing slices across the iterators seems important. My best attempt at creating an iterator that gzip decompresses [u8]
s passed in by another iterator is in a playground.
The error produced is:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/main.rs:48:50
|
48 | self.reader = gzip::Decoder::new(self.it.next().unwrap()).ok();
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 47:5...
--> src/main.rs:47:5
|
47 | / fn advance(&mut self) {
48 | | self.reader = gzip::Decoder::new(self.it.next().unwrap()).ok();
49 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:48:42
|
48 | self.reader = gzip::Decoder::new(self.it.next().unwrap()).ok();
| ^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 44:1...
--> src/main.rs:44:1
|
44 | / impl<'a> StreamingIterator for GunzipIter<'a> {
45 | | type Item = gzip::Decoder<&'a [u8]>;
46 | |
47 | | fn advance(&mut self) {
... |
50 | | fn get(&self) -> Option<&gzip::Decoder<&'a [u8]>> { Some(&(self.reader.unwrap())) }
51 | | }
| |_^
note: ...so that expression is assignable (expected std::option::Option<gzip::Decoder<&'a [u8]>>, found std::option::Option<gzip::Decoder<&[u8]>>)
--> src/main.rs:48:23
|
48 | self.reader = gzip::Decoder::new(self.it.next().unwrap()).ok();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
There's an example from the library:
use streaming_iterator::StreamingIterator;
pub struct FakeStreamingIterator<'a, I, T>
where
I: Iterator<Item = &'a &'a T>,
T: 'a + ?Sized,
{
inner: Box<I>,
current: Option<&'a &'a T>,
}
impl<'a, I, T> FakeStreamingIterator<'a, I, T>
where
I: Iterator<Item = &'a &'a T>,
T: ?Sized,
{
fn new(inner: I) -> FakeStreamingIterator<'a, I, T> {
FakeStreamingIterator {
inner: Box::new(inner),
current: None,
}
}
}
impl<'a, I, T> StreamingIterator for FakeStreamingIterator<'a, I, T>
where
I: Iterator<Item = &'a &'a T>,
T: ?Sized,
{
type Item = T;
fn advance(&mut self) {
self.current = self.inner.next();
}
fn get(&self) -> Option<&T> {
self.current.map(|x| *x)
}
}
That compiles fine, but a similar example that more closely matches my use-case doesn't:
use streaming_iterator::StreamingIterator;
pub struct FakeStreamingIterator<'a> {
inner: Box<StreamingIterator<Item = [u8]>>,
current: Option<&'a [u8]>,
}
impl<'a> FakeStreamingIterator<'a> {
fn new(inner: Box<StreamingIterator<Item = [u8]>>) -> FakeStreamingIterator<'a> {
FakeStreamingIterator {
inner: inner,
current: None,
}
}
}
impl<'a> StreamingIterator for FakeStreamingIterator<'a> {
type Item = [u8];
fn advance(&mut self) {
self.current = self.inner.next();
}
fn get(&self) -> Option<&[u8]> {
self.current.map(|x| x)
}
}
The error always comes down to lifetime mismatches, but I don't understand how to resolve this. The main differences, as I can see are:
- I'm holding a
Box
of a trait, rather than aBox
of a type. This is needed because the parent iterator is not known at compile time. - I'm using a slice rather than a reference to a reference. I don't understand why that would affect lifetimes.
In my mind, there are two logical lifetimes in play:
- The lifetime of the iterator
- The lifetime of the current slice.
The slice lifetime must be shorter than the iterator lifetime. I'm assuming there's a situation where Rust can guarantee that advance(&mut)
isn't called while there's an active borrow from the result of get(&)
alive, but am not sure how this can be written.
I've read a lot about borrows and lifetimes, but don't understand the difference in this situation.