Why does Iterator::all need the iterator to be mutable?


Keywords:iterator 


Question: 

I was using an iterator on a String's characters:

pub fn is_yelling(message: &str) -> bool {
    let letters = message.chars().filter(|c| c.is_alphabetic());
    message.chars().any(|c| c.is_alphabetic()) && letters.all(|c| c.is_uppercase())
}

This raises a compilation error:

error[E0596]: cannot borrow immutable local variable `letters` as mutable
 --> src/main.rs:3:51
  |
2 |     let letters = message.chars().filter(|c| c.is_alphabetic());
  |         ------- consider changing this to `mut letters`
3 |     message.chars().any(|c| c.is_alphabetic()) && letters.all(|c| c.is_uppercase())
  |                                                   ^^^^^^^ cannot borrow mutably

When I make letters mutable everything runs smoothly.

I do not understand why this necessary. The all method should not have to alter the the iterator. Like map or filter, which take self and not mut self as an argument.

My reference for map / filter / all.

I saw an issue on the matter, but no explanation was given.


2 Answers: 

Iterating anything requires mutating the iterator because Iterator::next takes &mut self. Checking all the values in the iterator requires iteration, therefore Iterator::all (and many similar methods) requires &mut self as well.

The all method should not have to alter the the iterator.

I am very interested to hear how you propose to check every value in an iterator without calling next.

Like map or filter

These methods return a new iterator, they do not call next. That being said, they could if they wanted because...

which take self and not mut self as an argument.

Mutability is a property of the owner of a variable. These two functions are equivalent:

fn example(mut a: String) {}
fn example(a: String) {
    let mut a = a;
}

Importantly, both look the same in the generated documentation — neither have mut in the signature. This is because it doesn't matter to the caller.



The iterator methods all and any take a mutable reference because they will be modifying the iterator by consuming its elements (note that next() also requires &mut self, since it inherently modifies the state of the iterator). In addition, the methods are short-circuiting, and do not necessarily consume all elements of the iterator. This means that the methods can give the iterator back to the caller, thus being able to continue consuming from it if so is desired.

let x = vec![1, 2, 5];
let mut it = x.into_iter();
assert!(it.any(|x| x > 1));
assert_eq!(it.next(), Some(5));

map or filter work differently, because they are iterator adaptors. Once invoked, the returned adaptor value will own the underlying iterator, and thus requires self to be moved. Values do not have to be bound to a mutable variable to be moved to another scope, even if they are modified later on in that context.