Rustlings 变量练习详解:Rust 的不可变性与 `mut`、遮蔽(Shadowing)与常量
2026/9/18 10:01:52 网站建设 项目流程

Rustlings 变量练习详解:Rust 的不可变性与mut、遮蔽(Shadowing)与常量

【免费下载链接】rustlings:crab: Small exercises to get you used to reading and writing Rust code!项目地址: https://gitcode.com/gh_mirrors/ru/rustlings

Rust 语言中,变量默认是不可变的(immutable),这一设计直接决定了所有 Rust 程序的编写方式。本文以 Rustlings 仓库中 exercises/01_variables/README.md 为核心,结合 6 个循序渐进的小练习(variables1 ~ variables6)、官方参考答案(solutions/01_variables/)与练习提示配置(rustlings-macros/info.toml),系统讲解变量的声明、类型推断、可变性、遮蔽以及常量与变量的区别。读完本文,你不仅能独立完成 01_variables 全部练习,还能理解 Rust 编译器在背后替你拦下了哪些易犯错误。

Rust 变量:默认不可变

与多数编程语言不同,Rust 中的变量绑定(variable binding)默认是不可变的。这意味着一旦把一个值绑定到某个名字上,就不能再修改这个值。Rustlings 的变量练习 README 开宗明义地写道:

In Rust, variables are immutable by default. When a variable is immutable, once a value is bound to a name, you can't change that value. You can make them mutable by addingmutin front of the variable name.

即:

  • 变量默认不可变;一旦值绑定到名字,就不能再改变它;
  • 通过在变量名前添加mut关键字,可以让变量变为可变。

这一设计是 Rust 内存安全承诺的重要组成部分:不可变性消除了"某个值在读取时被其他代码意外修改"这一类竞态与逻辑错误,让编译器可以在编译期就拒绝大量不安全的改写。

需要说明的是,"不可变"针对的是绑定(binding)本身:变量名不能再被重新赋值,而非该值内部的字段不可修改。真正的运行时只读约束需要借助const(见后文)或引用类型来实现。

let声明变量:类型推断与类型注解

Rust 使用let关键字创建新的变量绑定,形式为:

let x = 5; // 类型由编译器推断 let y: i32 = 42; // 显式类型注解
  • 类型推断:当没有显式注解时,Rust 会根据右侧的值推断类型。整数字面量的默认类型是i32
  • 类型注解:可以在变量名后加: 类型显式指定,例如let x: u8 = 42;。当需要非默认类型或编译器无法推断时,注解必不可少。

这一点在 variables2 的官方解答中有明确注释(solutions/01_variables/variables2.rs):

let x = 42; // 不注解时,Rust 推断为默认的 i32 // let x: u8 = 42; // 也可以显式注解为其他整数类型

未初始化变量不可使用

Rust 禁止读取未初始化的变量。variables3 要求你给let x: i32;赋一个值,否则编译器会直接报错——这是"读取不存在的值"这类 bug 在编译期被拦截的典型例子。官方解答(solutions/01_variables/variables3.rs)还展示了一种合法用法:先声明、后初始化,但初始化前绝不能使用:

let y: i32; // 先声明 y = 42; // 后赋值 println!("Number {y}"); // 此时才可读取

mut让变量可变

如果确实需要修改变量绑定的值,需要在let后加上mut关键字:

let mut x = 3; x = 5; // 合法:x 是可变的

variables4 正是这一知识点的实战:原练习中let x = 3;之后紧跟着x = 5;的重新赋值,编译必然失败。正确答案只需要把声明行改为let mut x = 3;(solutions/01_variables/variables4.rs)。

变量练习对应的提示文件 rustlings-macros/info.toml 也直白地指出:Rust 中变量绑定默认不可变,要重新赋值就必须使用mut

经验法则:仅在明确需要改写绑定的场景下使用mut;默认保持不可变,能让代码的意图更清晰,也让编译器替你检查更多潜在问题。

遮蔽(Shadowing):同名变量的重新声明

mut解决的是"改变值",但有些场景你其实想要的是一个新的、不同类型的同名变量。Rust 提供了一种更强大的机制:遮蔽(shadowing)——用let重新声明一个同名变量,新绑定会遮蔽旧的,且允许改变类型。

variables5 就是为练习遮蔽而设计的:一开始number是字符串"T-H-R-E-E",随后又要让number参与整数运算number + 2。直接改成mut没有意义,因为类型不匹配。官方解法(solutions/01_variables/variables5.rs)是:

let number = "T-H-R-E-E"; println!("Spell a number: {number}"); let number = 3; // 遮蔽:同名新绑定,类型从 &str 变成 i32 println!("Number plus two is: {}", number + 2);

info.toml中的提示(rustlings-macros/info.toml)特别强调了遮蔽的适用场景:当你只是想把值转换成不同类型、或想复用已有变量名时,遮蔽比mut更合适。

遮蔽与mut的关键区别:

维度mut可变绑定遮蔽(shadowing)
关键字let mut再次使用let声明同名变量
是否允许换类型不允许(类型一旦推断即固定)允许,新绑定可以有全新类型
生命周期同一绑定持续到作用域结束新绑定创建后旧绑定不可见
典型场景修改同一类型的值类型转换、复用变量名

常量(Constants):用const声明

除了变量,Rust 还有常量。variables6 引入了这一概念,info.toml中的提示(rustlings-macros/info.toml)总结了常量与变量的核心区别:

  • 常量用const声明,而不是let
  • 常量永远不可变,不存在mut版本;
  • 常量的类型必须显式注解,不能省略;
  • 常量可以声明在任何作用域(包括全局),并且必须在编译期就能确定值。

官方解答(solutions/01_variables/variables6.rs):

const NUMBER: u64 = 3; // 类型注解是必需的 fn main() { println!("Number: {NUMBER}"); }

变量与常量的对比:

维度变量(let常量(const
关键字let/let mutconst
可变性默认不可变,可用mut开启永远不可变
类型注解可省略(类型推断)必须显式注解
声明位置函数体内等局部作用域任意作用域,常用于全局
值确定时机运行时绑定编译期常量

逐题通关:variables1 ~ variables6 完整指南

Rustlings 中,01_variables 目录下的 6 个练习均为test = false的编译型练习(见 rustlings-macros/info.toml),即只需要让代码通过编译即可。下面逐题说明修复思路与官方答案。

variables1:补上let关键字

原代码(exercises/01_variables/variables1.rs)中x = 5;缺少声明关键字。提示指出:在main中创建新变量绑定需要一个关键字。解法是在x = 5;前补上let

fn main() { let x = 5; println!("x has the value {x}"); }

variables2:初始化变量以解决类型推断失败

原代码(exercises/01_variables/variables2.rs)中let x;之后直接参与x == 10的比较,编译器无法推断x的类型。提示引导你思考三种方案:加类型注解、给x赋值、或者两者都做。最简解法是直接初始化:

let x = 42; // 推断为 i32,与 10 同类型

也可以显式注解:let x: u8 = 42;。关键点是x的类型必须与10可比(同为整数类型)。

variables3:给变量赋值后才能使用

原代码(exercises/01_variables/variables3.rs)声明了let x: i32;却从未赋值就打印。解法:let x: i32 = 42;。如前面所述,也可以先声明后赋值,但绝不能在使用前保持未初始化。

variables4:用mut允许重新赋值

原代码(exercises/01_variables/variables4.rs)中x = 5;是"不要修改这一行"的重新赋值,所以只能改声明行:

let mut x = 3;

variables5:用遮蔽完成类型转换

原代码(exercises/01_variables/variables5.rs)要求"不改变变量名"地修复编译错误,且不能用mut(类型不同)。解法是遮蔽:

let number = "T-H-R-E-E"; let number = 3; println!("Number plus two is: {}", number + 2);

variables6:为常量补上类型注解

原代码(exercises/01_variables/variables6.rs)中const NUMBER = 3;缺少类型注解。解法:

const NUMBER: u64 = 3;

类型可以换成其他整数类型(如i32),但注解本身不可省略。

在 Rustlings 中运行与验证

这些练习属于"编译通过即算完成"的类型,不包含#[test]断言。在仓库根目录下:

# 进入下一道练习(变量系列从 variables1 开始) rustlings next # 运行当前练习并检查是否正确 rustlings run # 或直接指定练习运行 rustlings run variables1

当代码通过编译后,rustlings run会给出成功提示并自动进入下一题。想对照标准答案,可以直接查看 solutions/01_variables/ 目录下对应的同名文件,每份答案都附有解释性注释,是复习知识点的最佳素材。

小结

  • Rust 变量默认不可变,这是语言层面的安全设计;
  • 需要改写绑定时用let mut
  • 需要换类型或复用名字时用let遮蔽
  • 需要编译期确定的全局不可变值时用const,且必须写类型注解
  • 未初始化变量不可读取,编译器会在编译期拦截这类错误。

Rustlings 的变量练习与官方文档 The Rust Book 的 §3.1 "Variables and Mutability"(对应关系见 exercises/README.md 的练习章节映射表)一一对应。完成这一组练习后,你将具备编写正确、地道的 Rust 变量代码的基础能力。

【免费下载链接】rustlings:crab: Small exercises to get you used to reading and writing Rust code!项目地址: https://gitcode.com/gh_mirrors/ru/rustlings

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询