繁体   English   中英

在 Rust 中,“阴影”和“可变性”有什么区别?

[英]In Rust, what's the difference between "shadowing" and "mutability"?

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

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

哪些输出:

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

然而,由于 Rust 对阴影变量的看法,我们可以简单地这样做来改变仍然“不可变”的x

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

哪些输出(跳过细节):

The value of x is 5
The value of x is 6

有趣的是,这段代码也产生了上面的两行作为输出,尽管我们没有调用let而是在第一次x绑定到5时调用了mut

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

这种在如何(并非真的)保护变量免于重新分配方面的模糊性似乎与保护绑定到不可变(Rust 默认)变量的值的既定目标背道而驰。 来自同一章(其中还包含阴影部分):

当我们尝试更改我们之前指定为不可变的值时,我们会遇到编译时错误,这一点很重要,因为这种情况会导致错误。 如果我们的代码的一部分基于值永远不会改变的假设而运行,而我们代码的另一部分更改了该值,则代码的第一部分可能不会执行其设计的目的。 这种错误的原因事后很难追查,尤其是当第二段代码只是偶尔更改值时。

在 Rust 中,编译器保证当你声明一个值不会改变时,它真的不会改变。 这意味着当您阅读和编写代码时,您不必跟踪值可能发生变化的方式和位置。 因此,您的代码更容易推理。

如果我可以通过一个足够无辜的调用let我的不可变x这个重要特性被mut ,为什么我需要mut 有什么方法可以真正地,认真地让x不可变,这样就没有let x可以重新分配其值?

我相信混淆是因为您将名称与存储混为一谈。

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);
}

在此示例中,有一个名称 ( 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);
}

在此示例中,有一个名称 ( 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);
}

这输出:

The value of y is 5
The value of y is 5

这是因为更改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);
}

这将无法编译,因为您无法在借用x_0时对其进行变异。

Rust 关心防止通过引用观察到的不需要的突变效应。 这与允许遮蔽并不冲突,因为您在遮蔽时不会更改值,您只是在以其他任何地方都无法观察到的方式更改特定名称的含义。 阴影是严格的局部变化。

所以是的,你绝对可以保持x的值不被改变。 不能做的是保持名称x所指的内容不被更改。 最多,您可以使用像clippy类的clippy来拒绝将阴影视为 lint。

暂无
暂无

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

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