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

问题描述 投票:0回答:1

在《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 对

shadowing 变量的采用,我们可以简单地这样做来更改“不可变”的值 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

,而是在第一次 
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); }

如何(并非真正)保护变量免于重新分配的这种模糊性似乎与保护绑定到不可变值(Rust 默认情况下)变量的既定目标相矛盾。来自同一章(还包含

阴影部分):

当我们尝试这样做时,我们会遇到编译时错误,这一点很重要 更改我们之前指定为不可变的值,因为这 任何情况都可能导致错误。如果我们的代码的一部分运行在 假设一个值永远不会改变,而我们的另一部分 代码更改了该值,代码的第一部分可能是 不会做它设计的事情。造成此类错误的原因可以 事后很难追查,尤其是当第二次发生时 一段代码仅有时会更改值。

在 Rust 中,编译器保证当你声明一个值时 不会改变,真的不会改变。这意味着当你 阅读和编写代码,您不必跟踪如何以及 值可能会改变的地方。因此你的代码更容易推理 通过。

如果我可以通过对

x

 的足够无辜的调用来回避我的不可变 
let
 的这个重要功能,为什么我需要 
mut
?有没有什么方法可以让 
x
 变得不可变,这样就没有 
let x
 可以重新分配它的值?

variables rust immutability mutability shadowing
1个回答
66
投票
我认为造成混淆是因为您将名称与存储混为一谈。

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_0
x_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
 之类的东西来拒绝阴影作为 lint。

© www.soinside.com 2019 - 2024. All rights reserved.