在Rust中,"阴影"和"可变性"之间有什么区别?

d8a*_*nja 9 variables immutability mutability rust

Rust Book,Variables和Mutability的第3章中,我们对这个主题进行了几次迭代,以演示Rust中变量的默认,不可变行为:

fn main() {
    let x = 5;
    println!("The value of x is {}", x);
    x = 6;
    println!("The value of x is {}", x);
}
Run Code Online (Sandbox Code Playgroud)

哪个输出:

error[E0384]: cannot assign twice to immutable variable `x`
 --> src/main.rs:4:5
  |
2 |     let x = 5;
  |         -
  |         |
  |         first assignment to `x`
  |         help: make this binding mutable: `mut x`
3 |     println!("The value of x is {}", x);
4 |     x = 6;
  |     ^^^^^ cannot assign twice to immutable variable
Run Code Online (Sandbox Code Playgroud)

但是,由于Rust对阴影变量的处理,我们可以简单地这样做来改变"不可变"的值x:

fn main() {
    let x = 5;
    println!("The value of x is {}", x);
    let x = 6;
    println!("The value of x is {}", x);
}
Run Code Online (Sandbox Code Playgroud)

哪些输出(跳过细节):

The value of x is 5
The value of x is 6
Run Code Online (Sandbox Code Playgroud)

有趣的是,这段代码也产生了上面的一对行作为输出,尽管事实上我们没有调用let但是mut第一次x被绑定到5:

fn main() {
    let mut x = 5;
    println!("The value of x is {}", x);
    x = 6;
    println!("The value of x is {}", x);
}
Run Code Online (Sandbox Code Playgroud)

变量如何(实际上)不受重新分配的这种模糊性似乎与保护绑定到不可变的值的所述目标相反 - 由Rust默认变量.从同一章节(其中还包含阴影部分):

当我们尝试更改之前指定为不可变的值时,我们会遇到编译时错误,这很重要,因为这种情况可能会导致错误.如果我们的代码的一部分在假设值永远不会改变而代码的另一部分改变了该值的情况下运行,那么代码的第一部分可能不会按照它的设计去做.事实之后,这种错误的原因很难追查,特别是当第二段代码有时仅更改值时.

在Rust中,编译器保证当你声明值不会改变时,它确实不会改变.这意味着当您在阅读和编写代码时,您无需跟踪值的变化方式和位置.因此,您的代码更容易推理.

如果我可以使我的不可变的这个重要特征x与无辜的足够的电话一起步调let,为什么我需要mut?是否有某种方式可以真实地,认真地对待你们这些人是x不可改变的,以至于没有人let x可以重新分配它的价值?

DK.*_*DK. 16

我相信这种混乱是因为你将名称与存储混为一谈.

fn main() {
    let x = 5; // x_0
    println!("The value of x is {}", x);
    let x = 6; // x_1
    println!("The value of x is {}", x);
}
Run Code Online (Sandbox Code Playgroud)

在此示例中,有一个名称(x)和两个存储位置(x_0x_1).第二种let是简单地重新绑定名称x以引用存储位置x_1.该x_0存储位置是完全不受影响.

fn main() {
    let mut x = 5; // x_0
    println!("The value of x is {}", x);
    x = 6;
    println!("The value of x is {}", x);
}
Run Code Online (Sandbox Code Playgroud)

在此示例中,有一个名称(x)和一个存储位置(x_0).所述x = 6分配是直接改变存储位置的位x_0.

你可能会说这些做同样的事情.如果是这样,那你就错了:

fn main() {
    let x = 5; // x_0
    let y = &x; // y_0
    println!("The value of y is {}", y);
    let x = 6; // x_1
    println!("The value of y is {}", y);
}
Run Code Online (Sandbox Code Playgroud)

这输出:

The value of y is 5
The value of y is 5
Run Code Online (Sandbox Code Playgroud)

这是因为更改哪个存储位置x所指的存储位置绝对没有影响x_0,这是y_0包含指针的位置.然而,

fn main() {
    let mut x = 5; // x_0
    let y = &x; // y_0
    println!("The value of y is {}", y);
    x = 6;
    println!("The value of y is {}", y);
}
Run Code Online (Sandbox Code Playgroud)

这无法编译,因为您x_0在借用时无法进行变异.

Rust 通过引用观察防止不需要的突变效应.这与允许阴影没有冲突,因为你在阴影时不会改变值,你只是改变了某个特定名称的含义,而这种方式在其他任何地方都无法观察到.阴影是一种严格的局部变化.

所以是的,你绝对可以保持x改变的价值.你不能做的是保持名称x所指的变更.最多,您可以使用类似clippy拒绝阴影作为棉绒的东西.

  • 没有人对“不可变变量”这个表达感到震惊吗?它们不是反义词吗? (2认同)