简体   繁体   中英

Shadowing in Rust and Fighting the Borrow Checker

Every time I take user input I created a new variable (via shadowing) to get the input. I think this is inefficient and not the purpose of shadowing, how else can I efficiently reuse the variable input?

Without shadowing it gives the error cannot borrow "input" as mutable because it is also borrowed as immutable . As I understand taking user input requires a mutable reference.

use std::io; // Import for IO

fn main() {
    let name: &str;                 // Variables
    let balance: f32;               // Variables
    let interest: f32;              // Variables
    let mut input = String::new();  // Variables

    println!("Please enter your name: "); // Print
    io::stdin().read_line(&mut input).expect("failed to read from stdin");
    name = input.trim();
    println!("Please enter your bank account balance: "); // Print

    loop {
        let mut input = String::new(); // Remove this and I get an error
        io::stdin().read_line(&mut input).expect("failed to read from stdin");

        match input.trim().parse::<f32>() {
            Ok(_) => {
                balance = input.trim().parse().unwrap();
                break;
            },
            Err(_) => println!("Your balance cannot contain letters or symbols"),};
        }
    }

    println!("Please enter your interest rate percent: "); // Print
     
    loop {
        let mut input = String::new(); // Remove this and I get an error
        io::stdin().read_line(&mut input).expect("failed to read from stdin");
    
        match input.trim().parse::<f32>() {
            Ok(_) =>  {   
                interest = input.trim().parse().unwrap();
                break;
            },
            Err(_) => println!("Your balance cannot contain letters or symbols"),};       
        }
    }

    println!("{}, your gain from interest is : ${}", name, (interest * balance * 0.01)); // Print
}

Coming from Java I am perplexed on how borrowing works and when shadowing is a good idea. I understand that the old value still exists and any references to it which means if you don't need the old value anymore then you're taking up resources for no reason. Any advice is helpful, thanks.

The error tells you the problem:

error[E0502]: cannot borrow `input` as mutable because it is also borrowed as immutable
  --> src/main.rs:20:27
   |
13 |     name = input.trim();
   |            ----- immutable borrow occurs here
...
20 |     io::stdin().read_line(&mut input).expect("failed to read from stdin");
   |                           ^^^^^^^^^^ mutable borrow occurs here
...
47 |     println!("{}, your gain from interest is : ${}", name, (interest * balance * 0.01)); //Print
   |                                                      ---- immutable borrow later used here

input.trim() creates an immutable reference to input and stores it in name . If you remove the String::new() calls, then you are calling io::stdin().read_line(&mut input) which takes a mutable reference to input, but there is still an immutable reference to input in the name variable.

In Rust, you are not allowed an immutable reference and a mutable reference to exist at the same time, so the compiler gives an error.

You cannot really reuse the variable here, you need to clone or do what you are doing and create a new string entirely.

HexCoder's answer explains that you cannot reuse the String in input because it is borrowed by name . However, to make it reusable, all you need to do is copy input.trim() into a new String with its own buffer:

let name: String = input.trim().into();

Since name no longer borrows input , you can erase input and re-use its buffer. To erase a string, use String::clear :

input.clear(); // instead of `input = String::new();`

Here is a more complete example in which I also use pattern bindings to avoid parsing input twice, and move the declaration of balance and interest to when they can be immediately initialized.

See also

There are some subtleties to variable shadowing, especially when you take compiler optimization into account; these questions may also be useful:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM