The for
loop is taking ownership of the iterator. To use the iterator inside the loop body, you need to desugar the for
loop into while let
:
while let Some(i) = iter.next() {
if i == 3 {
iter.position(0);
}
println!("{}", i);
}
If you want to make your iterator usable from a for
loop, you'll need to invest a bit of extra effort. You can implement Iterator
for &BiIterator
, and use interior mutability for pos
, so position()
can take &self
:
// don't need RefCell because we're just mutating a number
use std::cell::Cell;
struct BiIterator<T> {
values: Vec<T>,
pos: Cell<usize>,
}
impl<T: Clone> Iterator for &BiIterator<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.pos.set(self.pos.get() + 1);
self.values.get(self.pos.get() - 1).cloned()
}
}
impl<T> BiIterator<T> {
pub fn position(&self, new_pos: usize) {
self.pos.set(new_pos);
}
pub fn prev(&mut self) {
self.pos.set(self.pos.get() - 1);
}
}
impl<T> std::convert::From<Vec<T>> for BiIterator<T> {
fn from(input: Vec<T>) -> Self {
Self {
values: input,
pos: Cell::new(0),
}
}
}
With these changes you can finally use for i in &iter
as per the compiler's original suggestion:
fn main() {
let iter = BiIterator::from(vec![1, 2, 3]);
for i in &iter {
if i == 3 {
iter.position(0);
}
println!("{}", i);
}
}
The above implements some additional changes:
- no need for the
Copy
bound on T
, since you're only cloning it. Any T
that is Copy
is automatically Clone
, and cloning it can be expected to just perform the cheap copy.
- bounds are almost never needed on the struct; put them just on the
impl
instead.
- replace the if/else if let/else chain with a
match
or, better yet, with Option::cloned()
.
for i in &iter
is not useful because it doesn't compile (as&iter
is not iterable), and wouldn't allow invokingposition()
inside the loop anyway. The proper solution is obvious to someone experienced in Rust, but not so to a beginner. – Chamblee