Reputation: 1371
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.
Upvotes: 3
Views: 1376
Reputation: 430671
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
orfilter
These methods return a new iterator, they do not call next
. That being said, they could if they wanted because...
which take
self
and notmut 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.
Upvotes: 12
Reputation: 29983
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.
Upvotes: 5