变量
在 Rust 中,变量的处理方式与其他编程语言(如 Python 或 Java)有很大不同。其核心设计理念是安全性和内存管理。
以下是关于 Rust 变量的核心知识点:
变量绑定
在很多编程语言中,我们会说“给变量赋值”。但在 Rust 中,官方术语通常是 “变量绑定” (Variable Binding) 。
- 语法 :
let x = 5; - 核心逻辑 :这个语句意味着我们将名字
x与值5绑定在一起。 - 为什么叫“绑定”?
- 模式匹配 :
let关键字后面跟着的实际上是一个 模式 (Pattern) 。例如,你可以这样写:let (a, b) = (1, 2);。这里 Rust 会把元组中的值分别绑定到a和b上。 - 所有权控制 :绑定不仅仅是内存地址的赋值,它还涉及到 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 的区别:
- 类型转换:使用
let遮蔽时,你可以改变变量的类型(例如从字符串变为数字),而mut变量的类型是固定的。 - 重新锁定:遮蔽后,新变量如果没有
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 在这里失效并释放