长安的 Rust 入门教程长安的 Rust 入门教程
首页
基础教程
进阶内容
Rust 官网
编程指南
首页
基础教程
进阶内容
Rust 官网
编程指南
  • 基础教程

    • 📚 基础教程
    • 第1章 - 认识 Rust
    • 第2章 - 安装 Rust
    • 第3章 - Hello World
    • 第4章 - 变量与可变性
    • 第5章 - 数据类型
    • /guide/06-functions.html
    • 第7章 - 控制流
    • 第8章 - 所有权
    • 第9章 - 引用与借用
    • 第10章 - 结构体
    • 第11章 - 枚举
    • 第12章 - 模式匹配
    • 第13章 - 错误处理
    • 第14章 - 集合类型
    • 第15章 - 模块系统
  • 实战项目

    • 第16章 - 实战项目:猜数字游戏
    • 第17章 - 实战项目:待办事项 CLI
    • 第18章 - 实战项目:简单 HTTP 服务器

第4章 - 变量与可变性

嗨,朋友!我是长安。

上一章我们写了第一个 Rust 程序,但只是打印了一些固定的文字。要写真正有用的程序,我们需要学习变量。

在 Rust 中,变量有一个非常独特的特性:默认不可变。听起来有点奇怪?别担心,我会用最简单的方式给你解释清楚。

🤔 什么是变量?

变量就像是一个盒子,里面可以存放数据。比如:

  • 存放一个数字:年龄、分数、价格
  • 存放一段文字:姓名、地址、消息
  • 存放布尔值:真或假

让我们看第一个例子:

fn main() {
    let x = 5;
    println!("x 的值是: {}", x);
}

运行后输出:

x 的值是: 5

这里:

  • let 关键字用来声明变量
  • x 是变量名
  • = 5 表示把 5 这个值赋给 x
  • println! 打印 x 的值

长安说

在其他语言里,变量通常用 var、let、const 等关键字声明。Rust 统一使用 let,简单明了。

🔒 变量默认不可变

现在来看 Rust 最特别的地方:变量默认是不可变的(immutable)。

什么意思呢?看这个例子:

fn main() {
    let x = 5;
    println!("x 的值是: {}", x);
    
    x = 6;  // ❌ 错误!不能修改不可变变量
    println!("x 的值是: {}", x);
}

如果你运行这段代码,编译器会报错:

error[E0384]: cannot assign twice to immutable variable `x`
 --> src/main.rs:5:5
  |
3 |     let x = 5;
  |         -
  |         |
  |         first assignment to `x`
  |         help: consider making this binding mutable: `mut x`
5 |     x = 6;
  |     ^^^^^ cannot assign twice to immutable variable

编译器说:"x 是不可变的,你不能给它赋值两次!"

长安说

你可能会问:"为什么要这样设计?这不是很麻烦吗?"

其实这是 Rust 的一个核心设计理念:默认安全。不可变变量可以帮助你:

  • 避免意外修改数据导致的 bug
  • 让代码更容易理解(值不会突然变化)
  • 提高程序的并发安全性

如果你真的需要修改变量,Rust 提供了明确的方式,我马上就会讲到。

🔓 可变变量(Mutable)

如果你需要修改变量的值,只需要在声明时加上 mut 关键字:

fn main() {
    let mut x = 5;  // 注意这里加了 mut
    println!("x 的值是: {}", x);
    
    x = 6;  // ✅ 现在可以修改了!
    println!("x 的值是: {}", x);
}

运行后输出:

x 的值是: 5
x 的值是: 6

mut 是 mutable(可变的)的缩写。

长安提醒

只有在真正需要修改变量时才加 mut。如果一个变量声明后从未被修改,编译器会给出警告,提醒你去掉不必要的 mut。

🎭 变量遮蔽(Shadowing)

Rust 有一个很有意思的特性叫变量遮蔽(shadowing)。你可以用相同的名字声明新变量,新变量会"遮蔽"旧变量:

fn main() {
    let x = 5;
    println!("第一个 x: {}", x);
    
    let x = x + 1;  // 用新值遮蔽旧的 x
    println!("第二个 x: {}", x);
    
    let x = x * 2;  // 再次遮蔽
    println!("第三个 x: {}", x);
}

输出:

第一个 x: 5
第二个 x: 6
第三个 x: 12

长安说

每次使用 let 声明变量时,实际上是创建了一个全新的变量,只是名字相同而已。旧变量被"遮蔽"了,不再能访问。

遮蔽 vs 可变变量

你可能会问:"遮蔽和可变变量有什么区别?看起来效果一样啊。"

其实有两个重要区别:

区别1:遮蔽可以改变类型

fn main() {
    let spaces = "   ";      // 字符串类型
    let spaces = spaces.len();  // 数字类型,这是允许的!
    println!("空格数: {}", spaces);
}

但如果用 mut,就不能改变类型:

fn main() {
    let mut spaces = "   ";
    spaces = spaces.len();  // ❌ 错误!类型不匹配
}

区别2:遮蔽创建的是不可变变量

fn main() {
    let x = 5;
    let x = x + 1;  // x 依然是不可变的
    x = 10;  // ❌ 错误!不能修改
}

长安说

遮蔽在处理数据转换时特别有用。比如读取用户输入(字符串)然后转换成数字,可以用同一个变量名,代码更简洁。

📝 变量命名规则

Rust 的变量命名有以下规则:

  1. 只能包含:字母、数字、下划线
  2. 不能以数字开头
  3. 区分大小写(age 和 Age 是不同的变量)
  4. 不能使用关键字(如 let、fn、mut 等)
  5. 推荐使用蛇形命名法(snake_case)
fn main() {
    // ✅ 好的变量名
    let age = 25;
    let user_name = "长安";
    let is_active = true;
    let total_count = 100;
    
    // ❌ 不好的变量名(虽然能编译通过)
    let a = 25;           // 太简短,不知道是什么
    let userName = "长安";  // 应该用 snake_case 而不是 camelCase
    let x1y2z3 = 100;      // 没有意义的名字
}

长安说

好的变量名应该见名知意。别人(或者一个月后的你)看到变量名就知道它是干什么的。

🔢 未使用的变量

如果你声明了一个变量但从未使用,Rust 会给出警告:

fn main() {
    let x = 5;  // 警告:变量 `x` 从未使用
}

如果你确实需要声明但暂时不用的变量,可以在名字前加下划线 _:

fn main() {
    let _x = 5;  // 没有警告了
}

📖 常量(Constants)

除了变量,Rust 还有常量。常量和不可变变量很像,但有几个重要区别:

const MAX_POINTS: u32 = 100_000;

fn main() {
    println!("最大分数: {}", MAX_POINTS);
}

常量的特点:

  1. 必须用 const 声明,不能用 let
  2. 必须标注类型(这里是 u32)
  3. 可以在任何作用域声明,包括全局作用域
  4. 只能设置为常量表达式,不能是运行时计算的值
  5. 命名用全大写 + 下划线(SCREAMING_SNAKE_CASE)
特性不可变变量常量
关键字letconst
必须标注类型否是
能否遮蔽是否
作用域块级可全局
命名规范snake_caseSCREAMING_SNAKE_CASE

长安说

什么时候用常量?当这个值:

  • 在整个程序运行期间都不会变
  • 需要在多个地方使用
  • 具有特定的含义(比如最大值、配置项等)

例子:MAX_USERS、PI、API_URL 等。

💡 小结

在这一章,我们学会了:

  • 使用 let 声明不可变变量(Rust 的默认行为)
  • 使用 let mut 声明可变变量
  • 使用变量遮蔽(shadowing)创建同名的新变量
  • 变量命名规则和最佳实践
  • 使用 const 声明常量

核心要点:

  • 变量默认不可变,需要修改时显式加 mut
  • 遮蔽允许重用变量名,甚至可以改变类型
  • 不可变性让代码更安全、更易理解

🚀 下一步

现在你知道如何声明变量了,但变量可以存放什么类型的数据呢?

下一章,我们会学习 Rust 的数据类型:整数、浮点数、布尔值、字符和字符串。

第5章 - 数据类型 →

💪 练习题

动手试试这些练习:

  1. 声明一个不可变变量 age,赋值为你的年龄,然后打印它
  2. 声明一个可变变量 count,初始值为 0,然后增加到 5,打印每次的值
  3. 使用变量遮蔽,将一个字符串 "123" 转换成数字(提示:.parse() 方法)
  4. 声明一个常量 PI,值为 3.14159,类型为 f64
答案示例
fn main() {
    // 练习1
    let age = 25;
    println!("我的年龄是: {}", age);
    
    // 练习2
    let mut count = 0;
    println!("count: {}", count);
    count = count + 1;
    println!("count: {}", count);
    count = count + 1;
    println!("count: {}", count);
    // ... 继续到 5
    
    // 练习3
    let number_str = "123";
    let number_str: i32 = number_str.parse().unwrap();
    println!("转换后的数字: {}", number_str);
    
    // 练习4
    const PI: f64 = 3.14159;
    println!("π 的值约为: {}", PI);
}
最近更新: 2025/12/26 18:01
Contributors: 王长安
Prev
第3章 - Hello World
Next
第5章 - 数据类型