Use Of & Qualifier In Rust

An extract from sample code in "The Rust Programming Language" is placed below:

let mut guess = String::new(); // (A)
io::stdin().read_line(&mut guess) // (B)
expect("Failed to read line");

It is seen that &mut is used in line (B), whereas in line (A), it is simply mut

I would be thankful for any clarification as to the use of & qualifier as shown above.

In The Rust Programming Language book, read section 4.2 on references, which introduces the &, and section 3.1 on mutability, which introduces mut.

let mut guess = … defines the variable guess in the current scope and states that the variable can be redefined (mutated) in later statements.

&mut guess is a unique read/write borrow of the variable guess; no other access to guess is permitted while that read/write borrow is active.

1 Like

Thanks TomP - for your kind clarification.

Could it then be concluded that in such a case, & qualifier would be needed only for mutable variables?

No.

I like the book lending analogy here:

I can give you a 'book', in which case it is now your book and you can read it, write in it, burn it do what you like with it. I no longer have the book after I have given it to you. I can never read it again.

I can give you a '&book', a reference to my book, a kind of view of it. In which case you can read it but you cannot write in it. You cannot burn it either, when you are done you give it back to me and I can continue to do whatever I like with it.

I can give you '&mut book', a mutable reference to my book. Now you can read it and you can write into it. But you cannot burn it. You have to give the modified book back to me at some point. Then I can see what you wrote in there.

3 Likes

...unless the book is given to you again (like every method with signature (self): Self does).

Nice analogy by ZiCog.

However, the point remains that declaring a variable as immutable, has the implicit protection that it is immune to any interference or alteration. As such, the need for using & prefix for such a variable is not quite clear.

I look forward to your views in this regard.

An important thing to understand with Rust is that there's a difference between the mutability of a binding, and the mutability of the thing contained within that binding.

For example, if you have a variable defined like so:

let mut foo = &bar;

This means that foo is a mutable binding containing an immutable reference to bar. This is not the same as let mut foo = bar, which would move the value out of the bar binding and into the foo binding, leaving bar inaccessible*.

Because the binding is mutable, the following would be valid:

let mut foo = &bar;
foo = &other;

But because the reference isn't mutable, this wouldn't be valid:

let mut foo = &bar;
bar.as_mut(); // A method that takes '&mut self'

* unless bar implements Copy, in which case bar gets copied into foo.

2 Likes

The & creates a borrow (as in @ZiCog's analogy), but just using a variable directly is owning it. Ownership implies responsibility for deallocating and destroying something (burning the book in @ZiCog's analogy). When you have borrowed something, all you can do when you get rid of it is to return it to its owner. Borrows allow you to use something without taking ownership. The alternative would be to allow multiple ownership, which is unsafe, as the following example shows:

let x = vec![1, 2, 3];
let y = x;

When x goes out of scope, the vector would be deallocated, but then uses of y would be accessing dangling memory. Worse, when y goes out of scope, the vector would try to be deallocated again, which would leave the allocator in very messed up state.

Because this is bad, Rust doesn't allow use of the variable x after y has been created, since ownership has been transferred to y. The variable y then has sole responsibility for deallocating.

Using a reference to borrow x avoids this problem, since ownership is not transferred:

let x = vec![1, 2, 3];
let y = &x;

Note that this only applies to types that don't implement Copy, since implementing Copy means a type doesn't point to memory that must be deallocated and is therefore safe to copy.

2 Likes