一、变量绑定 Variable Bindings
Rust 通过静态类型保证类型安全。声明变量绑定时可以手动标注类型;但绝大多数场景编译器能从上下文自动类型推导,不用手写类型注解。
使用 let 将值(字面量等)绑定到变量。
fn main() {
let an_integer = 1u32; // u32 无符号32位整数
let a_boolean = true; // bool 布尔值
let unit = (); // 单元类型 (),类似其他语言void
// 将 an_integer 的值拷贝给 copied_integer
let copied_integer = an_integer;
println!("An integer: {}", copied_integer);
println!("A boolean: {}", a_boolean);
println!("Meet the unit value: {:?}", unit); // {:?} 调试打印
// Rust 编译器会警告未使用的变量;变量名以下划线开头可以消除警告
let _unused_variable = 3u32;
let noisy_unused_variable = 2u32;
// 警告:未使用变量,改成 _noisy_unused_variable 消除警告
}Code language: JavaScript (javascript)
执行结果
An integer: 1
A boolean: true
Meet the unit value: ()Code language: JavaScript (javascript)
知识点:
_变量名告诉编译器“我故意不使用这个变量”,屏蔽 unused 警告;单纯下划线_是丢弃值,和_var有区别。
二、可变性 Mutability
默认所有变量绑定都是不可变(immutable),想要修改变量必须加上 mut 修饰符。
fn main() {
let _immutable_binding = 1; // 不可变变量
let mut mutable_binding = 1; // 可变变量
println!("Before mutation: {}", mutable_binding);
mutable_binding += 1; // 合法,可变变量允许修改
println!("After mutation: {}", mutable_binding);
_immutable_binding += 1;
// 编译报错!不能修改不可变绑定
}Code language: JavaScript (javascript)

编译器会输出清晰的错误信息,提示你尝试修改不可变变量。
三、作用域与变量遮蔽 Scope and Shadowing
变量绑定存在作用域,只存活在代码块 {} 内部。代码块是一对大括号包裹的语句集合。
fn main() {
// 存活于整个main函数
let long_lived_binding = 1;
// 内部代码块,更小的作用域
{
// 仅在当前块内有效
let short_lived_binding = 2;
println!("inner short: {}", short_lived_binding);
}
// 代码块结束,short_lived_binding 销毁
// 报错:外部作用域访问不到块内变量,读者可以打开注释观察
//println!("outer short: {}", short_lived_binding);
println!("outer long: {}", long_lived_binding);
}Code language: JavaScript (javascript)
变量遮蔽(Shadowing)
允许在内部作用域用同名 let 新建变量,遮蔽外层同名变量,二者是完全独立的绑定,不代表修改外层变量。
在其它的语言中,像下面这样,在内部代码块中如果出现同名的变量,会直接无法编译,例如C#
fn main() {
let shadowed_binding = 1;
{
println!("before being shadowed: {}", shadowed_binding);
// 新建同名变量,遮蔽外层
let shadowed_binding = "abc";
println!("shadowed in inner block: {}", shadowed_binding);
}
// 离开内部块,内部遮蔽失效,恢复外层变量
println!("outside inner block: {}", shadowed_binding);
// 在外部作用域再次遮蔽
let shadowed_binding = 2;
println!("shadowed in outer block: {}", shadowed_binding);
}Code language: JavaScript (javascript)
输出
inner short: 2
outer long: 1

let x = ...新建遮蔽,可以更换类型;mut x赋值修改 → 原地修改,类型不能变。
四、先声明、后初始化 Declare first
可以先声明变量,之后再赋值初始化;但是变量在使用前必须完成初始化。
Rust 禁止读取未初始化变量,防止未定义行为。
工程上不推荐声明和初始化隔很远,可读性差;尽量靠近使用位置定义变量。
fn main() {
// 仅声明绑定,暂不赋值
let a_binding;
{
let x = 2;
a_binding = x * x; // 在块内完成初始化
}
println!("a binding: {}", a_binding); //输出:4
let another_binding;
//println!("another binding: {}", another_binding); // 报错:使用未初始化变量,取消注释此行 观察
another_binding = 1;
println!("another binding: {}", another_binding); // 输出:1
}Code language: JavaScript (javascript)
取消上面的注销后,会报错误

五、冻结 Freezing
当可变变量被同名不可变变量遮蔽时,原数据会被「冻结」:
在这个作用域内无法修改,直到该不可变绑定走出作用域销毁。
fn main() {
let mut _mutable_integer = 7i32;
{
// 使用let遮蔽,生成不可变绑定,冻结原有数据
let _mutable_integer = _mutable_integer;
_mutable_integer = 50;
// 报错!当前作用域变量不可变,无法修改;注释此行
// 内部块结束,这个遮蔽绑定销毁
}
// 冻结解除,可以正常修改
_mutable_integer = 3;
}Code language: JavaScript (javascript)

总结
let创建变量绑定,默认不可变;let mut可变;- 类型大多自动推导,可手动标注
let x: u32 = 10;; - 变量受作用域限制,
{}创造局部范围; - Shadowing(遮蔽):
let 同名变量创建新变量,可换类型;和 mut 修改完全不同; - 变量必须初始化才能读取,禁止未初始化值;
- 可变变量被同名不可变遮蔽 → 冻结,暂时不能修改;
_变量名消除未使用警告;