Skip to content

变量基础

> 理解 Rust 变量不可变性的默认设计,掌握 let 与 let mut 的用法及编译器错误诊断。

变量声明

let 关键字

概念名称: let 用于声明变量绑定。

语法结构:
┌──────────────────────────────────────┐
│  let 变量名: 类型 = 值;               │
│   ↑     ↑      ↑    ↑                │
│   关键字 名字  可选  初始值            │
│                类型标注               │
│                                       │
│  let x = 5;        → 类型推断         │
│  let x: i32 = 5;   → 显式标注         │
└──────────────────────────────────────┘

最简示例

rust
fn main() {
    let x = 5;  // 类型推断为 i32
    println!("x = {}", x);
}
▶ Run

详细示例

rust
fn main() {
    // 声明一个变量
    let x = 5;
    println!("x = {}", x);

    // 变量默认是不可变的(immutable)
    // x = 6;  // ❌ 错误:不能给不可变变量重新赋值
    
    // 显式类型标注
    let y: i32 = 10;
    let z: f64 = 3.14;
}
▶ Run

关键代码说明:

代码含义为什么这样写
let x = 5声明不可变变量Rust 默认不可变,更安全
let x: i32 = 5显式类型标注当类型推断不确定时使用
// x = 6重新赋值被禁止编译器阻止意外修改

变量命名规则

rust
fn main() {
    // 推荐使用 snake_case(蛇形命名法)
    let my_variable = 10;
    let count = 20;

    // 可以使用下划线开头(表示暂未使用)
    let _unused = 5;

    // 可以覆盖外部变量(shadowing)
    let x = 5;
    let x = 10;  // 这是允许的
    println!("x = {}", x);  // 输出 10
}
▶ Run

可变性

mut 关键字

概念名称: mut 使变量可变。

语法结构:
┌──────────────────────────────────────┐
│  let mut 变量名 = 值;                 │
│      ↑                               │
│      可变标记                         │
│                                       │
│  let x = 5;     → 不可变(默认)      │
│  let mut x = 5; → 可变                │
└──────────────────────────────────────┘

最简示例

rust
fn main() {
    let mut x = 5;
    x = 10;  // ✅ 正确:可变变量可以重新赋值
    println!("x = {}", x);
}
▶ Run

详细示例

rust
fn main() {
    // 使用 mut 声明可变变量
    let mut y = 5;
    println!("y = {}", y);

    y = 10;  // ✅ 正确:y 是可变的
    println!("y = {}", y);

    // 不可变 vs 可变
    let a = 5;      // 不可变
    let mut b = 5;  // 可变

    // a = 6;       // ❌ 错误
    b = 10;         // ✅ 正确
}
▶ Run

为什么默认不可变

┌─────────────────────────────────────────────────────┐
│          为什么变量默认不可变?                      │
├─────────────────────────────────────────────────────┤
│                                                     │
│  1. 安全性                                           │
│     • 防止意外修改                                   │
│     • 减少 bug                                       │
│                                                     │
│  2. 并发安全                                         │
│     • 不可变数据天然线程安全                        │
│     • 编译器可以做得更好优化                         │
│                                                     │
│  3. 代码可读性                                       │
│     •  reader 知道值不会改变                         │
│     • 更容易推理代码行为                             │
│                                                     │
│  Rust 哲学:让正确的事情变得容易                     │
│                                                     │
└───────────────────────────────────────┘

语言对比:变量可变性

Rust vs 其他语言

┌─────────────────────────────────────────────────────┐
│              变量可变性对比                           │
├─────────────────────────────────────────────────────┤
│                                                     │
│  Java/C++:                                          │
│  ├── int x = 5;        // 默认可变                  │
│  ├── x = 10;           // ✅ 允许                   │
│  ├── final int y = 5;  // 需要显式标记不可变        │
│  └── 设计:可变是默认,不可变需额外声明              │
│                                                     │
│  Python:                                            │
│  ├── x = 5             // 可变                      │
│  ├── x = 10            // ✅ 允许                   │
│  ├── 无不可变变量语法                              │
│  └── 设计:全部可变                                 │
│                                                     │
│  Rust:                                              │
│  ├── let x = 5;        // 默认不可变                │
│  ├── x = 10;           // ❌ 编译错误               │
│  ├── let mut y = 5;    // 需要显式标记可变          │
│  ├── y = 10;           // ✅ 允许                   │
│  └── 设计:不可变是默认,可变需额外声明              │
│                                                     │
│  对比结论:                                          │
│  ├── Java/C++:安全需主动追求                      │
│  ├── Python:安全靠自觉                            │
│  ├── Rust:安全是默认                              │
│                                                     │
└─────────────────────────────────────────────────────┘

实际代码对比

rust
// Rust:默认安全
fn main() {
    let config = load_config();  // 不可变
    // config = new_config();    // ❌ 编译器阻止修改
    
    let mut counter = 0;         // 显式声明需要修改
    counter += 1;                // ✅ 允许
}
▶ Run
java
// Java:需要主动保护
public class Example {
    void run() {
        int config = loadConfig();  // 可被意外修改
        config = newConfig();       // ✅ 允许(可能是 bug)
        
        final int safeConfig = loadConfig();  // 需要显式 final
        // safeConfig = newConfig();          // ❌ 编译错误
    }
}

常见错误诊断

错误 1:修改不可变变量

错误代码

rust
fn main() {
    let x = 5;
    x = 10;  // 尝试修改不可变变量
}
▶ Run

编译器错误

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

解读错误信息

┌─────────────────────────────────────────────────────┐
│              错误信息解读                             │
├─────────────────────────────────────────────────────┤
│                                                     │
│  error[E0384]: cannot assign twice to immutable   │
│                variable `x`                         │
│  │                                                  │
│  │  错误码 E0384 = "不能给不可变变量赋值两次"       │
│  │  x 是不可变的,不能再次赋值                      │
│                                                     │
│  first assignment to `x`                           │
│  │                                                  │
│  │  说明:第一次赋值位置(let x = 5)              │
│                                                     │
│  cannot assign twice to immutable variable         │
│  │                                                  │
│  │  说明:尝试第二次赋值                            │
│  │  原因:变量不可变                                │
│                                                     │
│  help: make this binding mutable                   │
│  │                                                  │
│  │  建议:添加 mut 使变量可变                       │
│  │  解决方案:let mut x = 5;                        │
│                                                     │
│  关键:编译器告诉你原因和解决方案                   │
│                                                     │
└─────────────────────────────────────────────────────┘

修复方案

rust
// 方案 1:添加 mut(如果确实需要修改)
fn main() {
    let mut x = 5;  // 显式声明可变
    x = 10;         // ✅ 正确
}

// 方案 2:保持不可变(如果不需要修改)
fn main() {
    let x = 5;
    let x = 10;     // 使用变量遮蔽(shadowing)
    println!("{}", x);
}
▶ Run

错误 2:未初始化变量

错误代码

rust
fn main() {
    let x: i32;
    println!("{}", x);  // 使用未初始化变量
}
▶ Run

编译器错误

error[E0381]: used assignment is required but `x` is not assigned
 --> src/main.rs:3:20
  |
2 |     let x: i32;
  |         - help: consider assigning a value: `let x: i32 = <value>;`
3 |     println!("{}", x);
  |                    ^ used assignment is required but `x` is not assigned

解读与修复

错误码 E0381:使用了未赋值的变量

修复:
├── 方案 1:初始化变量
│   let x: i32 = 0;

├── 方案 2:使用类型推断(自动推断为 0)
│   let x = 0;

错误 3:类型不匹配

错误代码

rust
fn main() {
    let x: i32 = "hello";
}
▶ Run

编译器错误

error[E0308]: mismatched types
 --> src/main.rs:2:18
  |
2 |     let x: i32 = "hello";
  |                  ^^^^^^^ expected `i32`, found `&str`
  |
  = note: expected type `i32`
          found reference `&str`

解读与修复

错误码 E0308:类型不匹配

原因:
├── 声明类型:i32(整数)
├── 实际类型:&str(字符串)
├── 类型不兼容

修复:
├── 方案 1:修改值类型
│   let x: i32 = 42;

├── 方案 2:修改声明类型
│   let x: &str = "hello";

错误诊断速查

错误码错误类型原因快速解决
E0384修改不可变变量尝试给 let 变量赋值两次添加 mut
E0381未初始化变量使用未赋值的变量初始化变量
E0308类型不匹配值与声明类型不符修正类型

小结

本章核心:

  • let 声明变量,默认不可变
  • let mut 声明可变变量
  • Rust 默认不可变,主动追求安全
  • 编译器错误是最好的学习线索

练习题

详见:练习题