use std::iter::Peekable;
pub trait AdvanceWhile<I: Iterator> {
fn advance_while<P>(&mut self, predicate: P)
where
P: Fn(&I::Item) -> bool;
}
impl<I: Iterator> AdvanceWhile<I> for Peekable<I> {
fn advance_while<P>(&mut self, predicate: P)
where
P: Fn(&I::Item) -> bool,
{
while let Some(val) = self.peek() {
if predicate(val) {
self.next();
} else {
break;
}
}
}
}
Error:
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/main.rs:16:17
|
14 | while let Some(val) = self.peek() {
| ---- first mutable borrow occurs here
15 | if predicate(val) {
16 | self.next();
| ^^^^ second mutable borrow occurs here
...
20 | }
| - first borrow ends here
As Lukas Kalbertodt already said, this is a limitation of the borrow checker. Here I would like to show a more readable version:
You could rewrite the function into this:
The problem is that your original code could do this:
Accessing
val
after you callednext()
would allow you to access memory that was no longer valid, causing memory unsafety.As others have pointed out, your code doesn't actually do this, but current Rust uses lexical lifetimes, an overly-conservative approximation of how long a reference needs to be valid for. Future Rust should help constrain the logic without introducing unsafety.
If your value implements
Copy
, you can make use of that:This causes the value to be copied from the reference returned by
peek
. Since nothing is borrowed, the fact that you are going to mutate the iterator does not cause a problem.If your type implements
Clone
, you could clone the value, again disassociating it:If your type is neither
Copy
norClone
, you need to introduce a temporary variable for the boolean result. This clearly informs the compiler that the borrow returned bypeek
isn't needed beyond the equality check statement:See also:
Okay so this is not the best way of doing it but it might come in handy for more complicated cases...
Playpen
Typical case of lexical borrowing: the compiler is not yet able to understand that this is code is safe. So for the time being (until the so called non-lexical borrowing is implemented), try to rewrite your code. Like this, for example: