I'm a beginner to the Rust programming language, and I'm trying to create a toy program where I declare a (mutable) integer, but instead of changing that integer directly, I create a mutable reference to it and change it through there. Additionally, I want to create yet another mutable reference and change it again. All while printing out the variable value (before and after the assignments).
I'll call the original integer variable cat
; I'll call the first mutable reference dog
, and the second mutable reference I'll call bird
.
Here is my code:
fn main() {
let mut cat = 1;
println!("cat (before) = {}", cat); // => 1
// Make a dog so that modifying *dog modifies cat:
let dog = &mut cat;
println!("*dog = (before) {}", *dog); // => 1
*dog = 22;
println!("*dog (after) = {}", *dog); // => 22
// Make a bird that modyfing *bird modifies both *dog and cat:
let bird: &mut i32 = dog; // This line compiles...
// let bird = dog; // ...but this line gives a compile error.
println!("*bird (before) = {}", *bird); // => 22
*bird = 333;
println!("*bird (after) = {}", *bird); // => 333
// Print out the values, one final time:
println!();
println!("*bird (final) = {}", *bird); // => 333
println!("*dog (final) = {}", *dog); // Won't compile with "let bird = dog;"
println!("cat (final) = {}", cat); // => 333
}
As is, the program compiles and runs just fine. But take a look at the lines:
let bird: &mut i32 = dog; // This line compiles...
// let bird = dog; // ...but this line gives a compile error.
If you comment out that first line (the one with the &mut i32
explicit declaration) and un-comment out the second line (let bird = dog;
-- the one with the implicit declaration), then you will get the following compiler error:
error[E0382]: borrow of moved value: `dog`
But why? Are not those two lines of code essentially the same?
(The explanation for error E0382 says that a variable was used after its contents have been moved elsewhere. I could see how dog
's contents could have been moved to bird
, but after the final usage of bird
, wouldn't dog
get its contents back? Besides, even if dog
didn't get its contents back, how could it work with the explicit let bird: &mut i32 = dog;
declaration in the first place?)
Sure, the first line explicitly declares the bird
variable as a mutable reference to an i32
type, but doesn't the second line do that implicitly? (Maybe the second line uses i64
or u32
, but I don't think that would be a significant difference in this case.)
In other words, we established that dog
is a mutable reference to an integer at its declaration, so wouldn't writing:
let bird = dog;
implicitly establish that bird
is a mutable reference to an integer, just as dog
is?
Additionally, I'm also puzzled by the following behavior:
Obviously, I can fix the above compiler error by replacing the second line (the one with the implicit declaration) with the first (the one with the explicit declaration). However, I've also discovered that, instead of doing that, I can remove the compiler error by commenting-out/removing the println!("*dog (final) = {}", *dog);
line.
In other words, the lines:
let bird = dog;
and:
println!("*dog (final) = {}", *dog);
refuse to coexist. But remove one, and the program compiles and runs just fine. Why is that?
So basically I have two questions:
- How/why is the implicit declaration
let bird = dog;
different than thelet bird: &mut i32 dog;
declaration? (Aren't they essentially the same?) - Why does the
println!("*dog (final) = {}", *dog);
line work perfectly well with the explicitlet bird: &mut i32 dog;
declaration, but break with the implicitlet bird = dog;
declaration?
Thank you in advance!