Aviral Srivastava
Aviral Srivastava

Reputation: 4582

Are all inputs supposed to be mutable in Rust?

I wanted to input a value and assign it to a variable that is immutable (should be). How can I do that?

Currently, I am doing this:

use std::io;

fn main() {
    let mut a = 0;
    let mut b = 1;
    let mut nth_term = String::new();
    io::stdin().read_line(&mut nth_term);
}

But without &mut, it generates an error: types differ in mutability. If I remove mut from the declaration I get an error like this:

error[E0308]: mismatched types
 --> src/main.rs:5:27
  |
5 |     io::stdin().read_line(&nth_term).expect("I/O error");
  |                           ^^^^^^^^^ types differ in mutability
  |
  = note: expected mutable reference `&mut std::string::String`
                     found reference `&std::string::String`

How can I have something like this:

let input_var = input(); // or some other function that inputs the value and directly assigns it.

I tried reading the official documentation, the first few chapters, but in vain.

Upvotes: 2

Views: 621

Answers (1)

trent
trent

Reputation: 27915

Mutability in Rust follows the name, not the value. So if you have a value that is bound to a mutable variable, and you want it to be immutable, all you have to do is rebind it:

fn main() {
    let mut nth_term = String::new();
    io::stdin().read_line(&mut nth_term).expect("I/O error");
    let nth_term = nth_term;
    //  ^^^^^^^^-- no `mut`
}

Rebinding a value to the same name with a different mutability is common (see What does 'let x = x' do in Rust?).

You can also put the original binding in a block expression to minimize the scope of the mut variable:

fn main() {
    let nth_term = {
        let mut nth_term = String::new();
        io::stdin().read_line(&mut nth_term).expect("I/O error");
        nth_term
    };
}

BufRead::read_line is defined this way so that you don't need to allocate a new String for each new line read. The method has to take &mut because it can grow the string. Although you can iterate over input lines with stdin().lines(), which does yield owned Strings, there is no standard I/O function that reads a single line from stdin and returns a String (which you could simply bind to a non-mut variable). Of course, if you find yourself doing that a lot, you could just write your own function that contains the mut and returns, for instance, an io::Result<String>.

Upvotes: 4

Related Questions