When you return a reference from a function, its lifetime needs to be tied to something else. Otherwise, the compiler wouldn't know how long the reference is valid (the exception to this is a 'static
lifetime, which lasts for the duration of the whole program).
So we need an existing reference to the slices. One standard way to do this is to tie the reference to the iterator itself. For example,
struct Iter<'a> {
slice: &'a [u8; 100],
num: usize,
}
Then what you have works almost verbatim. (I've changed the names of the types and fields to be a little more informative).
impl<'a> Iterator for Iter<'a> {
type Item = &'a [u8];
fn next(&mut self) -> Option<Self::Item> {
if self.num >= 100 {
return None;
}
let res = &self.slice[10 * self.num..10 * (self.num + 1)];
self.num += 1;
Some(res)
}
}
Now, you probably still have an actual [u8; 100]
somewhere, not just a reference. If you still want to work with that, what you'll want is a separate struct that has a method to convert into A
. For example
struct Data {
array: [u8; 100],
}
impl Data {
fn iter<'a>(&'a self) -> Iter<'a> {
Iter {
slice: &self.array,
num: 0,
}
}
}
Thanks to lifetime elision, the lifetimes on iter
can be left out:
impl Data {
fn iter(&self) -> Iter {
Iter {
slice: &self.array,
num: 0,
}
}
}
(playground)
Just a few notes. There was one compiler error with [0u8; 100]
. This may have been a typo for [u8; 100]
, but just in case, here's why we can't do that. In the fields for a struct definition, only the types are specified. There aren't default values for the fields or anything like that. If you're trying to have a default for the struct, consider using the Default
trait.
Second, you're probably aware of this, but there's already an implementation of a chunk iterator for slices. If slice
is a slice (or can be deref coerced into a slice - vectors and arrays are prime examples), then slice.chunks(n)
is an iterator over chunks of that slice with length n
. I gave an example of this in the code linked above. Interestingly, that implementation uses a very similar idea: slice.chunks(n) returns a new struct with a lifetime parameter and implements Iterator
. This is almost exactly the same as our Data::iter
.
Finally, your implementation of next
has a bug in it that causes an out-of-bounds panic when run. See if you can spot it!