Reputation: 38228
Consider the following (dumb) program:
fn main() {
let mut array = &mut [1u8, 2u8, 3u8];
for &mut value in array {
}
}
It compiles and runs okay (though warns about unused variables/unnecessary mutability, as expected). But what does &mut
do in the for
statement?
It doesn't seem to give you a mutable reference into the array, since trying to assign value = 0;
results in the error:
error[E0384]: re-assignment of immutable variable `value`
Is &mut
here a no-op then?
Upvotes: 2
Views: 667
Reputation: 15559
So there's a few different things that's going on here. First, here's the answer:
fn main() {
let mut array = [1u8, 2u8, 3u8];
for value in &mut array {
*value = 0;
}
}
So. Where did you go wrong? Let's look at what value
is, like this:
for &mut value in array {
let () = value;
}
This gives this error:
= note: expected type `u8`
= note: found type `()`
So here, value
is a u8
. But why? Well, let's try this one:
for value in array {
let () = value;
}
This gives:
= note: expected type `&mut u8`
= note: found type `()`
So, value
here is an &mut u8
, a reference into the array. So by saying for &mut value
, we're saying "hey, this is going to be a mutable pointer to a u8
. We'd like value
to be the u8
value that's pointed at. This is because &mut value
is a pattern, which binds against a &mut T
and binds value
to the T
.
So, we remove the &mut
, since we don't want a copy of the value, we want to use it to modify what's pointed to. So that looks like this:
fn main() {
let mut array = &mut [1u8, 2u8, 3u8];
for value in array {
*value = 0;
}
}
This... compiles! Are we done? Well, let's try to print out array
, just to be sure:
fn main() {
let mut array = &mut [1u8, 2u8, 3u8];
for value in array {
*value = 0;
}
println!("{:?}", array);
}
This fails to compile:
error[E0382]: use of moved value: `array`
--> <anon>:7:22
|
3 | for value in array {
| ----- value moved here
We've destroyed array
by iterating. Why's that? Well, when you loop over an array like this, you're saying you want to loop by owner. But that's not actually what we want; we want to loop by mutable reference.
Arrays have a method to help with this:
fn main() {
let mut array = &mut [1u8, 2u8, 3u8];
for value in array.iter_mut() {
*value = 0;
}
println!("{:?}", array);
}
iter_mut
will iterate by &mut T
rather than by T
. So this works!
One last thing, though:
let mut array = &mut [1u8, 2u8, 3u8];
This says that array
is a &mut [u8; 3]
, that is, a mutable reference to an array, not an array itself. This probably isn't what you actually want, and it's not neccesary with our code. So we can remove the &mut
bit:
let mut array = [1u8, 2u8, 3u8];
And now you're at our first code sample.
Hope this helps!
Upvotes: 9
Reputation: 431529
Is
&mut
here a no-op then?
No, it's part of a pattern. Print the type of value
:
fn main() {
let mut array = &mut [1u8, 2u8, 3u8];
for &mut value in array {
let () = value;
// expected type `u8`
}
for value in array {
let () = value;
// expected type `&mut u8`
}
}
Upvotes: 1