Reputation: 549
As you know, a for in
loop owns its iterator for the duration of the loop if you pass it an iterator directly, like so:
let v = vec![...];
let mut i = v.iter();
for _ in i { }
As malbarbo observes, you can instruct for
to take a reference to i
by writing i.by_ref()
. However, you can't repeat that from inside the for loop:
for _ in i.by_ref() {
for _ in i.by_ref() {
// ^ error: cannot borrow `i` as mutable
// more than once at a time [--explain E0499]
break;
}
}
Understandably, the outer for
loop must modify its iterator, so it takes a mutable reference to it, and nobody else can call mutable methods on i
anymore. We can show this problem more directly like so:
for _ in i.by_ref() {
i.next(); // same error
}
One recourse is to make the outer for
a loop
and call i.next()
directly. Is there a prettier way to have our cake (the outer for loop iterates over i
) and eat it too (we can still advance i
inside the outer loop)?
Upvotes: 4
Views: 1845
Reputation: 22226
This is doable using a while let
expression.
let x = vec![1, 2, 3, 5, 4, 6, 7, 5, 8, 5];
let mut i = x.iter();
while let Some(v) = i.next() {
println!("First before inner loop: {}", v);
for v in i.by_ref() {
if *v == 5 {
println!("Found a 5");
break;
}
}
}
while let Some(v) = i.next()
is more or less directly equivalent to "for loop without borrowing the iterator". It, in turn, is essentially just:
loop {
match i.next() {
Some(v) => { loop_body },
_ => { break; },
};
}
Bonus: you can use while let
on pretty much any other expression you want to call repeatedly that returns a sum type.
Upvotes: 5