跳到主要内容

Rust 变量作用域

提示
  1. 变量作用域定义:在Rust中,变量的作用域指的是变量在其中有效的区域,通常是花括号{}内的代码块。
  2. 作用域内的变量访问:变量只能在其定义的作用域内访问和使用。尝试在作用域外部访问变量会导致编译错误。
  3. 变量遮蔽与冻结:Rust支持变量遮蔽,允许在内部作用域中重新声明相同名称的变量。变量冻结发生在不可变变量被遮蔽时,阻止对原变量的修改。

在计算机编程中,变量的作用域定义了变量可用的区域。例如,

fn main() {
// 这个变量在 main 函数块内有作用域
let age = 31;

}

这里,age 变量在 main() 函数的主体 {...} 内有作用域,

注意: Rust 中的每个变量都有一个在块内有效的作用域。块是由花括号 {} 包围的语句集合。

Rust 中变量作用域的工作原理

让我们通过一个示例来看看变量作用域是如何工作的,

fn main() {
// outer_var 变量的作用域在 main 函数代码块内
let outer_var = 100;

// 内部代码块的开始
{
// inner_var 变量的作用域仅在这个新代码块内
let inner_var = 200;
println!("inner_var = {}", inner_var);
}
// 内部代码块的结束

println!("inner_var = {}", inner_var);
println!("outer_var = {}", outer_var);
}

在这里,如果我们尝试在内部代码块外打印 inner_var,程序将无法编译,并且我们会遇到一个错误。

输出

error[E0425]: cannot find value `inner_var` in this scope
--> src/main.rs:13:32
|
13 | println!("inner_var = {}", inner_var);
| ^^^^^^^^^ 帮助:存在一个名称相似的本地变量:`outer_var`

由于我们尝试在内部代码块外打印变量,Rust 编译器找不到 inner_var 的作用域。

为了修复这个问题,我们可以这样做,

fn main() {
// outer_var 变量的作用域在 main 函数代码块内
let outer_var = 100;

// 内部代码块的开始
{
// inner_var 变量的作用域仅在这个新代码块内
let inner_var = 200;
println!("inner_var = {}", inner_var);
println!("outer_var 在内部块内 = {}", outer_var);
}
// 内部代码块的结束

println!("outer_var = {}", outer_var);
}

输出

inner_var = 200
outer_var 在内部块内 = 100
outer_var = 100

我们将 println!("inner_var = {}", inner_var); 从外部代码块中移除,程序现在如预期工作。

此外,我们可以在内部代码块中访问 outer_var,因为它的作用域在 main() 函数中。

下图展示了上述程序中变量作用域的工作原理,

Rust 中变量作用域的工作原理

Rust 中的变量遮蔽

在 Rust 中,当在特定作用域内声明的变量与外部作用域中声明的变量同名时,被称为 变量遮蔽

我们可以在同一程序的不同作用域块中使用相同的变量名称。

让我们看一个示例,

fn main() {
let random = 100;

// 内部块的开始
{
println!("内部块中未遮蔽之前的 random 变量 = {}", random);

// 这个声明遮蔽了外部的 random 变量
let random = "abc";

println!("内部块中遮蔽之后的 random = {}", random);
}
// 内部块的结束

println!("外部块中的 random 变量 = {}", random);
}

输出

random variable before shadowing in inner block = 100
random after shadowing in inner block = abc
random variable in outer block = 100

在这里,外部块中声明的 random 变量在内部块中被遮蔽。让我们看看这意味着什么,

let random = "abc";

内部块中的 random 变量值将遮蔽外部块的值,使得内部块拥有 "abc" 值。然而,外部块外的 random 变量值保持不变。

Rust 中的变量冻结

我们可以通过使用遮蔽和不可变性在 Rust 中冻结一个变量。一旦变量被冻结,在内部作用域中我们就无法改变变量的值。

让我们看一个例子。

fn main() {
let mut age = 1;

// 内部块的开始
{
// 通过不可变的 age 变量进行遮蔽
let age = age;

// 错误,age 变量在此作用域中被冻结
age = 2;

println!("内部块的 age 变量 = {}", age);
// age 变量超出作用域
}
// 内部块的结束

// 外部块中 age 变量未被冻结
age = 3;

println!("外部块的整数变量 = {}", age);
}

输出

error[E0384]: cannot assign twice to immutable variable `age`
--> src/main.rs:10:9
|
7 | let age = age;
| ---
| |
| first assignment to `age`
| 建议: 考虑将此绑定变为可变的: `mut age`
...
10 | age = 31;
| ^^^^^^^^ cannot assign twice to immutable variable

在上面的例子中,我们将外部块的可变变量 age 分配给了内部作用域中同名的不可变变量。

fn main() {
let mut age = 100;

{
let age = age;

}

}

通过这样做,我们用一个名为 age 的不可变变量遮蔽了可变的 age 变量。

现在,age 变量在内部块中被冻结,因为内部的 age 变量指向的是与外部块中 age 变量相同的值。

因此,我们无法在内部块中改变 age 的值,并且会遇到错误。

一旦我们离开内部块,age 的值就可以被改变了。

让我们看看变量冻结示例的工作版本。

fn main() {
let mut age = 100;

{
// 通过不可变的 age 变量进行遮蔽
let age = age;

println!("内部块的 age 变量 = {}", age);
// age 超出作用域
}

// 此作用域中 age 变量未被冻结
age = 3;

println!("外部块的 age 变量 = {}", age);
}

输出

内部块的 age 变量 = 100
外部块的 age 变量 = 3