Why should I add "mut" in "read_line" but not in "match"?

Hello,
On the page 25 of the book The Rust Programming Language, 2nd Edition, there is an exmaple

use std::io;
use std::cmp::Ordering;
use rand::Rng;

fn main() {
    println!("Guess the number!");
    let secret_number=rand::thread_rng().gen_range(1..=100);
    println!("Please input your guess.");
    let mut guess=String::new();
    io::stdin()
        .read_line(&mut guess)
        .expect("Failed to read line.");
    let guess:u32=guess
        .trim()
        .parse()
        .expect("Please type a number!");
    println!("You guessed: {guess}");
    match guess.cmp(&secret_number){
        Ordering::Less =>println!("Too small!"),
        Ordering::Greater=>println!("Too big!"),
        Ordering::Equal=>println!("You win!"),
    }
}

There is a mut before the guess in read_line(&mut guess) but not a mut after match. What is the reason and when should I add a mut?

The thing to focus on is that the mut comes after let.

let mut x = ... is similar to let x = ..., except that with mut it allows x to be mutated (modified).

Yes. So why should add mut in read_line but not after match?

read_line is a function that has one parameter. The type of the parameter is &mut String, which is a mutable reference to a String. The reason a mutable reference is needed is because read_line will modify the string. When you have a String in a variable, guess in this case, you pass it as this type with the syntax &mut guess. This passes a mutable reference to guess.

match is not a function. The expression after match does not need to be a mutable reference, because the rest of the match expression (everything in the braces) doesn't require it. This match statement reads the expression, but doesn't modify it.

(I have to say that Rust is very difficult to learn as your first language. You can do it. But an easier route is to first learn a simpler language like Python or Go, and then learn Rust.)

1 Like

You mean, what's the difference between read_line(&mut guess) and guess.cmp(&secret_number)? Simply put, that's different syntax for different types.

In Rust, references (or borrows, as they are also called) are full-blown types, just like numbers and strings are. For every type T, like i32 or String, there is a type of shared, or immutable, references to this type, &T, and a type of exclusive, or mutable, ones, &mut T. The syntax for creating such references mirrors the syntax for type itself: if you have value val of type T, you can create &val of type &T and &mut val of type &mut T.

As for why there was mutable reference in the first case and immutable one in the second case - well, that's just what the signature of each corresponding function does require: Stdin::read_line takes &mut String (it obviously needs it, since it has to modify the string), while u32::cmp takes &u32 (it needs only to look at the value, not to consume or change it).

3 Likes

IMHO let mut is a poorly designed language feature.
It's required for some cases of mutating values but not others, and the distinction is a deep technicality that is only explained circularly that this is how it's implemented and this is what the compiler wants.

If you take a mutable reference via binding to the whole object stored in the binding you need let mut, but if you reborrow or use a &mut reference already stored somewhere else, then you don't need let mut. You also don't need let mut when you mutate a temporary value even if that value has been moved from a non-mut binding.

In short: just add mut where the compiler wants it, and don't worry about it. It's an unimportant lint. The real mutability is only controlled by ownership and &mut references.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.