Rust 可变变量怎么定义?两种常见方式一次讲清

编程狮(w3cschool.cn) 2026-10-10 07:03:47 浏览数 (34)
反馈

在 Rust 里,变量默认是不可变的,这是它保证内存安全的第一道关卡。当你确实需要修改一个值时,主要有两条路:用 let mut 声明一个可变绑定,或者用 let 重新绑定(变量遮蔽)给同一个名字赋新值。两种方式都能让“值发生变化”,但语义和适用场景完全不同。很多从 C、C++ 转过来的开发者,一开始会因为忘了写 mut 被编译器拦下来。本文用最小示例讲清两种写法的差异、各自的边界,以及编译报错时怎么修,看完你就能按场景选对写法。

Rust 怎么定义可变变量?

先看结论

先给你一张选型表,省得在两种写法之间纠结:

你想做的事 推荐写法 原因
同一个变量在作用域内反复被修改 let mut 语义明确,编译器允许原地修改
基于旧值算出新值并换个类型 变量遮蔽 let x = x + 1 可以顺手换类型,更安全
只是一次性初始化 默认不可变 let 不变就不写 mut,符合 Rust 习惯

一句话记住:要“反复改”,用 mut;要“基于旧值换新值”,用遮蔽;都不要就保持默认不可变,这是 Rust 推荐的默认姿态。

一、let mut:声明可变绑定

Rust 的变量绑定默认不可变,想让它能被重新赋值,必须在 let 后面加 mut(mutable 的缩写)。这是最常见、最直接的可变写法。

fn main() {
    let mut count = 0;
    count = 1;
    println!("count = {}", count);
}

上面这段先声明了一个可变的 count,初始为 0,随后把它改成 1 再打印。预期结果(未在本机执行):程序编译运行后输出 count = 1,说明 count 在被 mut 声明后可以被重新赋值。如果你还不熟悉 Rust 的变量与所有权基础,可以先过一遍 Rust 入门教程 的前几章再回来读。

需要安装的运行时很简单:用 rustup 装好工具链后,新建项目用 cargo new demo,运行用 cargo run,检查改动用 cargo build。从边界上说,mut 只作用于当前绑定所在的作用域,离开作用域后绑定就失效,这和 C、C++ 里的局部变量作用域一致。性能上,mut 是零成本抽象,编译后和不加 mut 没有运行时差别,所以放心用。

二、变量遮蔽:用 let 重新绑定同名变量

第二种让“值变化”的方式不是修改原绑定,而是用同一个名字再声明一次,新绑定会“遮蔽”旧绑定。这种方式的特点是可以顺手换类型。

fn main() {
    let x = 5;
    let x = x + 1; // 同名重新绑定,基于旧值算出新值
    println!("x = {}", x);
}

这段里第一个 x 是 5,第二个 x 基于它算出 6 并遮蔽了前者。预期结果(未在本机执行):程序运行后输出 x = 6。注意遮蔽后旧 x 在后续代码里不可再访问,不存在“两个 x 同时存在”的情况。

这种方式在 C 语言里没有对应物,熟悉 C 语言教程 的开发者可能会觉得别扭,但它很适合“先读入字符串、再解析成数字”这种类型转换场景:第一次 let s = "42" 是字符串,第二次 let s = s.parse::<i32>() 就变成了整数,名字不变却换了类型。如果你从 C 或 C++ 转来,理解这点的关键是记住 Rust 的遮蔽不是修改原变量,而是每次 let 都生成一个全新的绑定;调试时若发现旧值还在作用域里被引用,优先检查是不是遮蔽点写错了位置,而不是怀疑编译器。相比之下,C++ 教程 里类型一旦确定就难以在同一名字上变更,这也是 Rust 设计上更强调显式的原因。

三、两种方式的横向对比与选型

维度 let mut 变量遮蔽
是否修改变量本身 是,原地修改 否,生成新绑定
能否换个类型 否,类型固定 能,可换类型
旧值是否还能访问 能 被遮蔽后不能
适用场景 循环计数、状态累加 读入后转换、计算中间值

选型建议:当你需要在循环里不断累加、或在函数内多次更新某个状态时,用 let mut 最自然;当你只是基于旧值算出另一个值、甚至要换个类型时,用变量遮蔽更干净,也避免了把变量设成可变后意外被改。两者都不是“更好”,而是对应不同的意图。

let mut 与变量遮蔽两种写法横向对比

四、踩坑清单

下面这几条是新手最容易卡住的点,每条都给了现象、原因和修复办法。

  • 现象:写了 let x = 1; x = 2;,编译器报错 cannot assign twice to immutable variable。
    原因:Rust 默认绑定不可变,没写 mut 就不能二次赋值。
    修复:如果确实要反复改,改成 let mut x = 1; x = 2;。

  • 现象:想用 mut 又想换类型,结果编译失败。
    原因:mut 只让值可变,类型仍是第一次声明时定死的。
    修复:改用变量遮蔽 let x = ...; let x = 新类型的值;,遮蔽允许换类型。

  • 现象:遮蔽之后,旧值似乎“还能用”,逻辑乱了。
    原因:遮蔽只是名字复用,旧绑定在遮蔽点之后就不可访问,误以为还能用是理解偏差。
    修复:明确每个同名 let 的生效范围,必要时换不同名字避免混淆。

  • 现象:在 C/C++ 习惯里顺手写 mut 却用在非绑定位置,直接语法错。
    原因:Rust 的 mut 只出现在 let 后面或引用类型里,不能像 C++ 的 mutable 那样到处用。
    修复:确认自己是在声明可变绑定,而不是在套用 C++ 的 mutable 关键字语义。

Rust 可变变量写法怎么选?

总结

Rust 定义可变变量就两件事:反复改同一值用 let mut,基于旧值换新值(可换类型)用变量遮蔽,其余情况保持默认不可变。

要点带走:

  • 默认不可变,要改才加 mut,这是 Rust 的安全默认;
  • mut 是零成本抽象,不影响运行时性能;
  • 变量遮蔽能换类型,适合读取后转换的场景;
  • 忘了写 mut 的报错信息很明确,补上即可。

下一步如果你在写循环计数或状态机,建议优先用 let mut;遇到“读入字符串再转数字”这类转换,用遮蔽最顺手。

延伸学习

想把 Rust 的基础打牢,可以按这个顺序来:

  1. 那篇 Rust 为什么依然流行 从设计和安全性角度讲了它值得学的理由,适合建立整体认知;
  2. Go 与 Rust 全面对比 能帮你理解两门系统级语言在可变性与内存模型上的取舍,做技术选型时有参考。

常见问题

Q:为什么 Rust 变量默认不可变?

A:不可变是 Rust 保证内存安全和并发安全的第一道关卡,它让编译器能在编译期就拦下大量“意外修改”的 bug。需要改时显式写 mut,等于主动声明这里会变化,代价只是多敲几个字母。

Q:let mut 和变量遮蔽能混用吗?

A:可以。常见做法是先用 let mut 声明一个会变化的状态,在个别步骤用 let x = x + 1 这种遮蔽顺手换类型。只要注意遮蔽后旧绑定不再可访问,逻辑上不会冲突。

Q:Rust 的 mut 和 C++ 的 mutable 是一回事吗?

A:不是。Rust 的 mut 用在 let 后面,表示这个绑定可以被重新赋值;C++ 的 mutable 用在类成员上,表示即使在 const 对象里该成员也能改。两者语义不同,不能套用。

0 人点赞