3

I'm reading chapter two of The Rust Programming Language and something I don't understand caught my eye in here:

use std::io;

fn main() {
    println!("Guess the number!");

    println!("Please input your guess.");

    let mut guess = String::new();

    io::stdin().read_line(&mut guess)
        .expect("Failed to read line");

    println!("You guessed: {}", guess);
}

On code line 5, it declares a mutable variable with let mut guess = String::new(), but on the next line the argument for read_line() also has a mut keyword.

If the variable was defined as mutable in the first place, then why do we use mut again instead of just using the reference like this:

io::stdin().read_line(&guess).expect("Failed to read line");

If the type is defined for the variable, then when we use reference, shouldn't the type (mut) exist by default?

samayo
  • 16,163
  • 12
  • 91
  • 106
  • 5
    You should have kept reading :) "For now, all you need to know is that like variables, references are immutable by default. Hence, you need to write `&mut guess` rather than `&guess` to make it mutable. (Chapter 4 will explain references more thoroughly.)" – HFBrowning Oct 08 '18 at 22:27
  • yeah, i read that but I didn't want to skip the lesson, I'm reading a page per day and not understanding now would mess up my rythm ... that doc was so thorough until that point :) ... – samayo Oct 08 '18 at 22:30

3 Answers3

7

TL;DR: This is a design decision. The Rust compiler could, reasonably, infer whether mutability is necessary or not; however to a human reader it may not be obvious.


Long Story

If you look at Rust's predecessors, you will find that the use of reference arguments in C++ is not universally appreciated. In C++:

foo.call(bar);

only the definition of call will let you know whether bar is passed by value, const reference or mutable reference. As a result, the Google Style Guide is infamous for mandating pass-by-pointer for any modifiable argument, so as to distinguish at the call side whether a variable may be modified by the call, or not.

In designing Rust, there has been a large and deliberate emphasis on explicitness. The reasoning is that code is read more often than it is written, and therefore syntax and semantics should be optimized for reading and understanding.

There is a tension between explicitness and concision, so explicitness is not always preferred, but it often is.

In the case of mutable references, given the rules surrounding borrow-checking and the impact of mutable borrows on them, explicitness was preferred.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
5

Because you can have either an immutable reference to a mutable variable or a mutable reference to a mutable variable. The keyword mut selects which type of reference you'd like to create.

let mut foo = 1;
example1(&foo);     // May not modify `foo`
example2(&mut foo); // May modify `foo`

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • How does the first two lines make sense? if `foo` is type mutable, shouldn't it stay that way the entire cycle of process? thanks also for the answer – samayo Oct 09 '18 at 00:05
  • @ANW the type of `foo` is `i32` — mutability is not a property of that type. The type of the argument to `example` is `&i32` and the type of the argument to `example2` is `&mut i32`. Just because something is mutable doesn't mean that you always want to mutate it. Knowing that something cannot be changed is more powerful. – Shepmaster Oct 09 '18 at 00:14
  • 2
    @ANW actually the type that counts here isn't the type of `foo`, but the type of the argument for `example1` and `example2`. Since the compiler knows that `example1` takes an `&i32` parameter and `example2` takes an `&mut i32`, the `mut` in the function call is indeed redundant **for the compiler**. It is however useful **for the programmer who reads the code** who can then know at a glance if a function call risks mutating a parameter. Remember that you spend a lot more time reading than writing code. – Jmb Oct 09 '18 at 06:23
3

Remember that by default in Rust all is immutable, when you create a reference to something by using & by default this create a reference to something immutable, at least for the reference, the value itself is allowed to be mutable, the real mutable state of the value doesn't matter.

That is a little counter intuitive when you come from language where all is mutable. You don't need to explicitly tell that something is mutable, it's the default behavior. The need to explicitly write that a reference to something is immutable when we create it almost don't exist.

So to create a reference to something mutable, one must explicitly use &mut. This is a rule, the compiler know that the value can be mutate and could do it for you but Rust ask you to write it explicitly, it's as simple as that.

Stargateur
  • 24,473
  • 8
  • 65
  • 91