Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

变量

在 Rust 中,变量的处理方式与其他编程语言(如 Python 或 Java)有很大不同。其核心设计理念是安全性内存管理

以下是关于 Rust 变量的核心知识点:

变量绑定

在很多编程语言中,我们会说“给变量赋值”。但在 Rust 中,官方术语通常是 “变量绑定” (Variable Binding)

  • 语法let x = 5;
  • 核心逻辑 :这个语句意味着我们将名字 x 与值 5 绑定在一起。
  • 为什么叫“绑定”?
    • 模式匹配let 关键字后面跟着的实际上是一个 模式 (Pattern) 。例如,你可以这样写:let (a, b) = (1, 2);。这里 Rust 会把元组中的值分别绑定到 ab 上。
    • 所有权控制 :绑定不仅仅是内存地址的赋值,它还涉及到 Rust 核心的所有权 (Ownership) 系统。当一个值绑定到一个变量名时,这个变量名就“拥有”了这个值。

使用下划线忽略未使用的变量

Rust 编译器非常注重代码的整洁。如果声明了一个变量但从未使用过它,编译器会报出警告(Warning),认为这可能是代码逻辑上的疏忽。

A. 使用 _ (纯下划线)

如果你完全不关心某个值,可以使用 _。它会立即丢弃该值,不会进行任何绑定。

fn main() {
    let _ = 5; // 值被直接丢弃, 不绑定到任何名字, 你之后无法通过任何名字访问这个 5
    let _ = some_function_returns_result(); // 我调用了函数,但我不在乎返回值
}
fn some_function_returns_result() -> i32 {
    42
}

B. 使用下划线开头 (如 _x)

如果你想保留这个变量(可能为了调试或者为了以后扩展),但现在暂时不用,又不希望看到编译器的警告,可以在变量名前加一个下划线。

fn main() {
    let x = 5;     // ⚠️ 编译器会警告:unused variable: `x`
    let _y = 10;   // ✅ 编译器会保持沉默,因为它看到了下划线前缀
}

cargo run:

#![allow(unused)]
fn main() {
warning: unused variable: `y`
 --> src/main.rs:3:9
  |
3 |     let y = 10;
  |         ^ help: 如果 y 故意不被使用,请添加一个下划线前缀: `_y`
  |
  = note: `#[warn(unused_variables)]` on by default
}

不可变性

在 Rust 中,变量默认是不可变的。一旦你为一个变量绑定了值,就不能再修改它。

fn main() {
    let x = 5;
    x = 6; // ❌ 编译错误!不能对不可变变量二次赋值
}

为什么要这样做?

通过默认不可变,Rust 保证了数据的安全性。在多线程环境下,你可以确信一个变量的值不会在你不注意的时候被其他代码修改。


可变变量

如果你需要修改某个变量,必须显式地加上 mut 关键字。

fn main() {
    let mut x = 5;
    println!("x 的值是: {}", x);
    x = 6; // ✅ 允许修改
    println!("现在 x 的值是: {}", x);
}

变量遮蔽

Rust 允许你声明一个与现有变量同名的新变量。这被称为“遮蔽”。

fn main() {
    let x = 5;
    let x = x + 1; // 遮蔽了之前的 x
  
    {
        let x = x * 2; // 在当前作用域内再次遮蔽
        println!("内部作用域中 x 的值: {}", x); // 12
    }

    println!("外部作用域中 x 的值: {}", x); // 6
}

遮蔽与 mut 的区别:

  1. 类型转换:使用 let 遮蔽时,你可以改变变量的类型(例如从字符串变为数字),而 mut 变量的类型是固定的。
  2. 重新锁定:遮蔽后,新变量如果没有 mut,它依然是不可变的。

常量

常量类似于不可变变量,但有严格的区别:

  • 使用 const 关键字。
  • 必须显式注明类型(例如 i32)。
  • 可以在任何作用域声明(包括全局)。
  • 只能赋值为“常量表达式”,不能是函数调用的结果或运行时计算的值。
const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;
fn main() {
    println!("三小时的秒数: {}", THREE_HOURS_IN_SECONDS);
}

作用域

变量在 Rust 中是“块级作用域”的。变量在声明的大括号 {} 内有效,超出范围后,变量会被释放 (Drop)

fn main() {
    let s = "hello"; // s 进入作用域
    {
        let x = 10; // x 进入作用域
    } // x 在这里失效并释放
    println!("s 的值是: {}", s); // ✅ 可以访问 s
} // s 在这里失效并释放