I am testing a custom bi-directional iterator in rust but i ran into error
error[E0382]: borrow of moved value: `iter`
--> src/main.rs:40:13
|
37 | let mut iter = BiIterator::from(vec![1, 2, 3]);
| -------- move occurs because `iter` has type `BiIterator<i32>`, which does not implement the `Copy` trait
38 | for i in iter {
| ----
| |
| `iter` moved due to this implicit call to `.into_iter()`
| help: consider borrowing to avoid moving into the for loop: `&iter`
39 | if i == 3 {
40 | iter.position(0);
| ^^^^^^^^^^^^^^^^ value borrowed here after move
|
note: this function takes ownership of the receiver `self`, which moves `iter`
CodePudding user response:
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. With those changes you'll be able to use for i in &iter as the compiler suggested:
// 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: Clone> 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: Clone> std::convert::From<Vec<T>> for BiIterator<T> {
fn from(input: Vec<T>) -> Self {
Self {
values: input,
pos: Cell::new(0),
}
}
}
fn main() {
let iter = BiIterator::from(vec![1, 2, 3]);
for i in &iter {
if i == 3 {
iter.position(0);
}
println!("{}", i);
}
}
As an aside, the above implements some improvements:
- no need for
Copybound onT, since you're only cloning it. AnyTthat isCopyis automaticallyClone, 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
implinstead. - replace the if/else if let/else chain with a
matchor, better yet, withOption::cloned().
