讲解
Rust 的变量用 let 声明,并且默认不可变(immutable)——这是 Rust 与大多数语言相反的设计。不可变是默认项,意味着每当你看到 let x = 5,就可以确信 x 在这段作用域里永远是 5,阅读代码时心智负担小得多;想修改必须显式加 mut(mutable),让「这里会变」成为代码里显眼的标记。
试图修改不可变变量不是风格问题,而是编译错误。编译器这一拦看着烦,实则把一整类「某个值在别处被悄悄改掉」的 bug 消灭在编译期。多线程场景下这个约束的价值会成倍放大(第 24 章)。
遮蔽(shadowing)是 Rust 特有的能力:用 let 再次声明同名变量,前一个变量被「遮蔽」,之后的代码看到的是新变量。它和 mut 的区别很关键——遮蔽是创建新变量,可以改变类型;mut 是原地修改,类型不能变。对「同一个逻辑值的多步变换」(比如字符串去空格再转数字),遮蔽既安全又顺读。
最后是常量 const:必须用 const 关键字、必须标注类型、只能赋编译期可求值的表达式、全大写加下划线命名(SCREAMING_SNAKE_CASE)。常量在所有作用域都可声明,且永远不可变——连 mut 都不行。
示例
不可变是默认值,可变要显式声明:
fn main() {
let x = 5;
println!("x = {x}");
let mut y = 10;
println!("y 初始为 {y}");
y = 20;
println!("y 现在是 {y}");
assert_eq!(x, 5);
assert_eq!(y, 20);
}
如果试图修改不可变变量,编译会直接失败(本教程的构建脚本会验证这段代码确实编译不过):
// compile-fail: 修改不可变变量
fn main() {
let x = 5;
x = 6;
println!("{x}");
}
编译器给出的报错大意如下,注意它连修复建议都写好了:
error[E0384]: cannot assign twice to immutable variable `x`
--> main.rs:3:5
|
2 | let x = 5;
| - first assignment to `x`
| help: consider making this binding mutable: `mut x`
3 | x = 6;
| ^^^^^ cannot assign twice to immutable variable
遮蔽可以连类型一起换;常量则恒定不变:
const MAX_PLAYERS: u32 = 100_000;
fn main() {
let spaces = " ";
let spaces = spaces.len(); // 遮蔽:从 &str 变成 usize
let mut count = spaces;
count += 1; // mut 只能改值,类型还是 usize
println!("空格数 {spaces},加一后 {count},上限 {MAX_PLAYERS}");
assert_eq!(count, 4);
}
常见坑
- 满屏 mut:把每个变量都标 mut 等于关掉了编译器的保护,还会收到 unused mut 警告。只在真的需要修改时加。
- 分不清遮蔽和 mut:let 重复声明是遮蔽(新变量、可换类型);不带 let 的赋值是修改(要求原变量是 mut、类型不变)。
- 给 const 赋运行时值:const 的值必须在编译期确定,函数调用结果、用户输入都不行——那种场景用 let。
- 警告当错误忽视:编译器对未使用变量的警告(unused variable)往往指向逻辑漏洞——本来想用的值没用上,先看警告再继续。
小结
let 默认不可变,mut 显式开修改权限;遮蔽用同名新变量做变换;const 是编译期常量。这些约定让「值在哪里会变」一目了然。下一章认识标量类型。