简体   繁体   English

在 Rust 中隐藏并与借用检查器作斗争

[英]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 .如果没有阴影,它会导致错误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.来自 Java,我对借用的工作方式以及何时隐藏是一个好主意感到困惑。 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 . input.trim()创建一个对 input 的不可变引用并将其存储在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.如果删除String::new()调用,那么您正在调用io::stdin().read_line(&mut input) ,它接受对输入的可变引用,但在name变量中仍然存在对输入的不可变引用。

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.在 Rust 中,不允许不可变引用和可变引用同时存在,因此编译器会报错。

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 . HexCoder 的回答解释了您不能在input重用String ,因为它是由name借用的。 However, to make it reusable, all you need to do is copy input.trim() into a new String with its own buffer:但是,为了使其可重用,您需要做的就是将input.trim()复制到一个带有自己的缓冲区的新String

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

Since name no longer borrows input , you can erase input and re-use its buffer.由于name不再借用input ,您可以擦除input并重新使用其缓冲区。 To erase a string, use String::clear :要擦除字符串,请使用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. 这是一个更完整的示例,其中我还使用模式绑定来避免对input两次解析,并将balanceinterest的声明移至可以立即初始化的位置。

See also也可以看看

There are some subtleties to variable shadowing, especially when you take compiler optimization into account;变量阴影有一些微妙之处,尤其是当您考虑编译器优化时; these questions may also be useful:这些问题也可能有用:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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