Reputation: 361
I have a circular buffer like this:
struct CircularBuffer<T: Copy> {
seqno: usize,
data: Vec<T>,
}
And I want to create an external struct being an iterator. This struct would refer to the internal data vector of the CircularBuffer
like this one:
struct CircularBufferIterator<'a, T: 'a + Copy> {
buffer: &'a CircularBuffer<T>,
position: usize,
limit: usize,
}
This is the best I could come up with that actually compiles. Can you please suggest a better way to express that the CircularBufferIterator
depends on the CircularBuffer
object?
What troubles me is T: 'a + Copy
. I wonder if it is possible or it makes sense to say that not the T
type, but CircularBuffer<T>
is the one CircularBufferIterator
depends on.
The part I don't see is why do I need to add the 'a
lifetime to T
. Cannot that be T: Copy
, without a lifetime? In other words, I cannot see a case when T
reference outlives the CircularBuffer
. It is the CircularBuffer
reference that outlives the CircularBufferIterator
.
The CircularBuffer
and the context comes from this blog post.
Upvotes: 2
Views: 704
Reputation: 430554
why do I need to add the
'a
lifetime toT
You aren't adding a lifetime to T
; you are saying that whatever T
is chosen, it can only contain references that outlive 'a
. If that wasn't the case, then we might have a reference to a type that has a reference that is now invalid. Using that invalid reference would lead to memory unsafety; a key thing that Rust seeks to avoid.
I originally thought you were asking how to remove the Copy
bound, so here's all that I typed up.
One change would be to remove the Copy
bound from CircularBuffer
but leaving it on the implementation of the methods. Then you don't need it on the iterator at all:
struct CircularBuffer<T> {
seqno: usize,
data: Vec<T>,
}
struct CircularBufferIterator<'a, T: 'a> {
buffer: &'a CircularBuffer<T>,
position: usize,
limit: usize,
}
Another change would be to completely eschew the direct reference to the CircularBuffer
altogether, and keep direct iterators into the Vec
:
struct CircularBufferIterator<'a, T: 'a> {
first: std::slice::Iter<'a, T>,
second: Option<std::slice::Iter<'a, T>>,
}
However, looking at the Iterator
implementation, I see it returns a T
, not a &T
, so you ultimately need a type that is Copy
or Clone
. You'll note that the standard library doesn't require this because it returns a reference to the item in the collection. If you do need a non-reference, that's what into_iter
or Iterator::cloned
is for.
Upvotes: 3