Rust 术语概念大全
本文档整理了 Rust 编程语言中的所有核心术语概念,包含标准解释和易懂解释。
目录
一、基础概念
1. 变量 (Variable)
标准解释:使用 let 关键字声明的命名存储位置,默认不可变。
易懂解释:就像一个贴了标签的盒子,用来存放数据。默认情况下,盒子里的东西不能换(不可变),但加上 mut 就可以换了。
let x = 5; // 不可变变量,盒子封死了
let mut y = 10; // 可变变量,盒子可以换东西
y = 20; // OK
// x = 6; // 错误!不能修改
2. 可变性 (Mutability)
标准解释:变量值是否可以被修改的属性。Rust 默认不可变,需使用 mut 关键字显式声明可变。
易懂解释:就是"能不能改"。默认不能改(安全!),想改就得加 mut。
3. 常量 (Constant)
标准解释:使用 const 关键字声明的编译期常量,必须注明类型,不可更改,可在任何作用域声明。
易懂解释:永远不能变的值,编译时就确定了,像个刻在石头上的数字。
const MAX_POINTS: u32 = 100_000; // 必须注明类型
与不可变变量的区别:
- 常量编译时确定,变量运行时确定
- 常量不能使用
mut - 常量可在全局作用域声明
4. 遮蔽 (Shadowing)
标准解释:使用相同的变量名声明新变量,新变量会遮蔽前一个变量。
易懂解释:用同一个名字创建新变量,旧的被"遮住"了。就像给新员工用了离职员工的名字,大家只认新来的。
let x = 5;
let x = x + 1; // x = 6,新的 x 遮蔽了旧的
let x = "hello"; // 甚至可以改变类型!
5. 标量类型 (Scalar Types)
标准解释:表示单个值的类型,包括整数、浮点数、布尔值和字符。
易懂解释:最简单的数据类型,一个值就是一块数据。
| 类型 | 说明 | 例子 |
|---|---|---|
| 整数 | i8, i16, i32, i64, i128, u8... | 42, -1 |
| 浮点数 | f32, f64 | 3.14 |
| 布尔值 | bool | true, false |
| 字符 | char (Unicode) | 'a', '中', '😀' |
6. 复合类型 (Compound Types)
标准解释:将多个值组合成一个类型,包括元组(Tuple)和数组(Array)。
易懂解释:把多个值打包在一起的类型。
元组:可以放不同类型,固定长度
let tup: (i32, f64, u8) = (500, 6.4, 1);
let (x, y, z) = tup; // 解构
let first = tup.0; // 索引访问
数组:相同类型,固定长度
let arr: [i32; 5] = [1, 2, 3, 4, 5];
let first = arr[0];
let repeat = [3; 5]; // [3, 3, 3, 3, 3]
7. 函数 (Function)
标准解释:使用 fn 关键字定义的代码块,可接受参数并返回值。
易懂解释:一段有名字的代码,可以接收输入、产生输出。
fn add(a: i32, b: i32) -> i32 {
a + b // 表达式作为返回值(无分号)
}
fn no_return() { // 返回单元类型 ()
println!("hello");
}
8. 语句与表达式 (Statement vs Expression)
标准解释:
- 语句:执行操作但不返回值的指令,以分号结尾
- 表达式:计算并产生值,没有分号
易懂解释:
- 语句:做事,不给结果。就像你做完作业没告诉老师分数。
- 表达式:做事,给结果。就像考试后老师给你打分。
let y = { // 代码块是表达式
let x = 3; // 语句
x + 1 // 表达式(无分号),作为整个代码块的返回值
};
// y = 4
9. 控制流 (Control Flow)
标准解释:决定代码执行路径的结构,包括条件判断和循环。
易懂解释:控制程序"往哪走"的命令。
if 表达式
let number = 6;
let result = if number % 2 == 0 { "偶数" } else { "奇数" };
循环
loop {
println!("无限循环!");
break; // 退出
}
for i in 0..5 {
println!("{}", i); // 0, 1, 2, 3, 4
}
while count > 0 {
count -= 1;
}
二、所有权系统
1. 所有权 (Ownership)
标准解释:Rust 的核心内存管理机制,遵循三条规则:
- Rust 中每个值都有一个所有者
- 同一时刻只能有一个所有者
- 当所有者离开作用域,值会被丢弃
易懂解释:每个数据都有一个"主人",同一时间只能有一个主人。主人走了,数据就扔了。就像借东西,只能借给一个人,你走了东西就得还回去。
{
let s = String::from("hello"); // s 是所有者
} // s 离开作用域,内存释放
2. 移动 (Move)
标准解释:将值的所有权从一个变量转移到另一个变量。移动后,原变量不再有效。
易懂解释:把东西送给别人,你就没有了。就像把房子过户给别人,你不能再住了。
let s1 = String::from("hello");
let s2 = s1; // s1 的所有权移动给 s2
// println!("{}", s1); // 错误!s1 已经无效
println!("{}", s2); // OK
3. 克隆 (Clone)
标准解释:深拷贝,创建数据的完整副本。需要类型实现 Clone trait。
易懂解释:复印一份,原来的还在。就像复印文件,两份都可以用。
let s1 = String::from("hello");
let s2 = s1.clone(); // 深拷贝
println!("{} {}", s1, s2); // 两个都有效
4. 复制 (Copy)
标准解释:简单类型的值在赋值时会自动复制。类型需实现 Copy trait。
易懂解释:基本数据类型(数字、布尔等)太小了,直接复制一份,不用"移动"。
let x = 5;
let y = x; // i32 实现了 Copy,自动复制
println!("{} {}", x, y); // 两个都能用
实现了 Copy 的类型:
- 所有整数、浮点数类型
- bool、char
- 元素都是 Copy 的元组
5. 作用域 (Scope)
标准解释:变量有效的代码区域,通常由大括号 {} 定义。
易懂解释:变量"活着的范围"。出了这个范围,变量就没了。
{
let s = String::from("hello"); // s 进入作用域
// 使用 s
} // s 离开作用域,自动释放
三、引用与借用
1. 引用 (Reference)
标准解释:指向数据的指针,允许访问数据但不拥有它。使用 & 创建。
易懂解释:借东西用一下,但不归你所有。就像去图书馆借书,看完得还回去。
let s = String::from("hello");
let r = &s; // r 是 s 的引用
println!("{}", r); // 通过引用访问
2. 借用 (Borrowing)
标准解释:创建引用的行为。分为不可变借用(&T)和可变借用(&mut T)。
易懂解释:借东西这个过程。可以借来看看(不可变),也可以借来改改(可变)。
fn borrow_example() {
let mut s = String::from("hello");
let r1 = &s; // 不可变借用
let r2 = &s; // 可以多个不可变借用
println!("{} {}", r1, r2);
let r3 = &mut s; // 可变借用
r3.push_str(" world");
println!("{}", r3);
}
3. 借用规则
标准解释:
- 可以有多个不可变引用,或
- 可以有一个可变引用
- 但不能同时存在可变和不可变引用
- 引用的作用域不能超过被引用值的作用域
易懂解释:
- 要么大家一起看(多个不可变引用)
- 要么一个人改(一个可变引用)
- 不能一边改一边看(数据竞争!)
let mut s = String::from("hello");
let r1 = &s; // OK
let r2 = &s; // OK
// let r3 = &mut s; // 错误!已有不可变引用
println!("{} {}", r1, r2);
// 此后不可变引用结束
let r3 = &mut s; // 现在 OK
4. 悬垂引用 (Dangling Reference)
标准解释:指向已释放内存的引用。Rust 编译器会在编译时阻止这种情况。
易懂解释:引用了已经不存在的东西。就像你借了一本书,但图书馆把书烧了。Rust 编译器会阻止这种危险操作。
fn dangle() -> &String { // 错误!
let s = String::from("hello");
&s // s 在函数结束时被释放
} // 返回的引用指向已释放的内存
fn no_dangle() -> String { // 正确!
let s = String::from("hello");
s // 转移所有权,而不是返回引用
}
四、生命周期
1. 生命周期 (Lifetime)
标准解释:引用有效的作用域范围。Rust 使用生命周期标注确保引用始终有效。
易懂解释:引用能活多久。就像图书馆借书有借期,过了期限书就无效了。
// 生命周期标注语法
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
2. 生命周期标注 (Lifetime Annotation)
标准解释:使用 'a 等符号标注引用的生命周期关系,告诉编译器引用之间的关系。
易懂解释:给引用贴个"保质期"标签,告诉编译器它们之间的时间关系。
// 'a 表示 x、y 和返回值生命周期相同
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
// 结构体中的生命周期
struct ImportantExcerpt<'a> {
part: &'a str, // part 的生命周期不能短于结构体
}
3. 生命周期省略规则
标准解释:编译器自动推断生命周期的三条规则:
- 每个引用参数都获得一个生命周期参数
- 如果只有一个输入生命周期,它被赋给所有输出生命周期
- 如果有
&self或&mut self,self 的生命周期赋给所有输出生命周期
易懂解释:编译器很聪明,很多时候不需要你标注生命周期,它会自己猜。
// 省略前
fn first_word<'a>(s: &'a str) -> &'a str { ... }
// 省略后(编译器自动推断)
fn first_word(s: &str) -> &str { ... }
4. 静态生命周期 (Static Lifetime)
标准解释:'static 表示引用可以在程序的整个运行期间有效。字符串字面量就拥有静态生命周期。
易懂解释:永远活着,程序不死它不死。比如你代码里写的 "hello" 这个字符串。
let s: &'static str = "hello world"; // 字符串字面量
五、类型系统
1. 结构体 (Struct)
标准解释:自定义数据类型,用于组合多个相关的值。
易懂解释:自定义的"数据容器",把相关的数据打包在一起。
// 常规结构体
struct User {
username: String,
email: String,
active: bool,
}
// 元组结构体
struct Color(i32, i32, i32);
// 单元结构体(无字段)
struct AlwaysEqual;
2. 枚举 (Enum)
标准解释:定义一个类型,可以是几种不同变体之一。
易懂解释:一个变量可能有几种不同的"身份",枚举就是把这些身份列出来。
enum Message {
Quit, // 无数据
Move { x: i32, y: i32 }, // 结构体式
Write(String), // 元组式
ChangeColor(i32, i32, i32), // 元组式
}
// 经典的 Option 枚举
enum Option<T> {
Some(T),
None,
}
// 经典的 Result 枚举
enum Result<T, E> {
Ok(T),
Err(E),
}
3. 方法 (Method)
标准解释:在 impl 块中定义的函数,第一个参数是 self,表示调用该方法的对象。
易懂解释:属于某个类型的函数,用 . 调用。
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
// 关联函数(无 self)
fn new(width: u32, height: u32) -> Self {
Self { width, height }
}
// 方法(有 self)
fn area(&self) -> u32 {
self.width * self.height
}
// 可变方法
fn scale(&mut self, factor: u32) {
self.width *= factor;
self.height *= factor;
}
}
let rect = Rectangle::new(10, 20); // 关联函数
println!("{}", rect.area()); // 方法调用
4. 关联函数 (Associated Function)
标准解释:在 impl 块中定义但不以 self 为参数的函数,通常用作构造函数。
易懂解释:属于类型但不属于实例的函数,用 :: 调用。就像工厂生产产品。
let s = String::from("hello"); // from 就是关联函数
let v = Vec::new(); // new 也是关联函数
5. 类型别名 (Type Alias)
标准解释:使用 type 关键字为现有类型创建别名。
易懂解释:给类型起个外号,用起来更方便。
type Kilometers = i32; // Kilometers 就是 i32 的别名
type Thunk = Box<dyn Fn() + Send + 'static>;
let x: Kilometers = 5;
6. 新类型模式 (Newtype Pattern)
标准解释:使用元组结构体包装一个类型,创建一个新的、不同的类型。
易懂解释:给现有类型穿上"马甲",变成新类型,增加类型安全性。
struct Miles(f64);
struct Kilometers(f64);
// 编译器会把它们当作不同类型
let miles = Miles(10.0);
let km = Kilometers(16.09);
// miles + km // 编译错误!类型不同
六、模式匹配
1. match 表达式
标准解释:强大的模式匹配结构,穷尽所有可能的模式。
易懂解释:超级版的 switch,必须处理所有情况,不会漏掉任何分支。
enum Coin {
Penny,
Nickel,
Dime,
Quarter(UsState), // 带数据的变体
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter(state) => { // 绑定值的模式
println!("State quarter from {:?}", state);
25
}
}
}
2. if let 表达式
标准解释:只关心一种模式的简化写法,处理 match 的一种情况。
易懂解释:只关心一种情况,其他忽略。是 match 的简化版。
let some_value = Some(3);
// match 写法
match some_value {
Some(3) => println!("three"),
_ => (),
}
// if let 写法(更简洁)
if let Some(3) = some_value {
println!("three");
}
3. while let 条件循环
标准解释:当模式匹配成功时继续循环。
易懂解释:只要模式匹配就继续循环。
let mut stack = Vec::new();
stack.push(1);
stack.push(2);
stack.push(3);
while let Some(top) = stack.pop() {
println!("{}", top); // 3, 2, 1
}
4. 模式类型
标准解释:Rust 支持多种模式匹配形式。
易懂解释:模式就是你要匹配的"形状"。
// 字面量模式
let x = 1;
match x {
1 => println!("one"),
2 => println!("two"),
_ => println!("anything"),
}
// 命名变量模式
let x = Some(5);
match x {
Some(y) => println!("matched, y = {:?}", y),
None => println!("None"),
}
// 多重模式
let x = 1;
match x {
1 | 2 => println!("one or two"),
_ => println!("anything"),
}
// 范围模式
let x = 5;
match x {
1..=5 => println!("one through five"),
_ => println!("something else"),
}
// 解构模式
let point = (3, 5);
match point {
(0, y) => println!("on y axis at {}", y),
(x, 0) => println!("on x axis at {}", x),
(x, y) => println!("at ({}, {})", x, y),
}
// 忽略值
let numbers = (2, 4, 8, 16, 32);
match numbers {
(first, _, third, _, fifth) => {
println!("Some numbers: {}, {}, {}", first, third, fifth);
}
}
// 绑定值的模式
let x = Some(5);
match x {
Some(y @ 1..=5) => println!("got a number 1-5: {}", y),
Some(y) => println!("got something else: {}", y),
None => println!("None"),
}
5. 解构 (Destructuring)
标准解释:将复合类型拆分成其组成部分。
易懂解释:把打包的东西拆开,拿出里面的内容。
// 解构结构体
struct User {
name: String,
age: u32,
}
let user = User { name: String::from("Alice"), age: 30 };
let User { name, age } = user;
// 解构枚举
enum Message {
Quit,
Move { x: i32, y: i32 },
}
let msg = Message::Move { x: 10, y: 20 };
match msg {
Message::Move { x, y } => println!("move to ({}, {})", x, y),
_ => (),
}
七、错误处理
1. panic!
标准解释:Rust 的恐慌机制,导致程序终止并打印错误信息。
易懂解释:程序遇到无法处理的错误,直接崩溃退出。就像汽车出了大问题,直接停车。
panic!("crash and burn");
// 数组越界会 panic
let v = vec![1, 2, 3];
v[99]; // panic!
2. Result<T, E>
标准解释:用于可恢复错误的枚举类型,包含成功 Ok(T) 和失败 Err(E) 两个变体。
易懂解释:函数可能成功返回结果,也可能失败返回错误。Result 把两种情况都包起来。
use std::fs::File;
use std::io::ErrorKind;
fn open_file() {
let f = File::open("hello.txt");
let f = match f {
Ok(file) => file,
Err(error) => match error.kind() {
ErrorKind::NotFound => match File::create("hello.txt") {
Ok(fc) => fc,
Err(e) => panic!("创建文件失败: {:?}", e),
},
other_error => panic!("打开文件失败: {:?}", other_error),
},
};
}
3. unwrap 和 expect
标准解释:
unwrap():返回Ok中的值,遇到Err则 panicexpect("msg"):同上,但可以自定义错误信息
易懂解释:简单粗暴地获取结果。成功了给你值,失败了程序崩溃。
let f = File::open("hello.txt").unwrap(); // 失败时 panic
let f = File::open("hello.txt").expect("无法打开文件"); // 失败时 panic 并显示自定义信息
4. ? 运算符
标准解释:错误传播运算符,如果 Result 是 Err 则提前返回,是 Ok 则解包值。
易懂解释:遇到错误就往上抛,没错误就继续执行。简单省事。
fn read_file() -> Result<String, io::Error> {
let mut f = File::open("hello.txt")?; // 出错则返回 Err
let mut s = String::new();
f.read_to_string(&mut s)?; // 出错则返回 Err
Ok(s)
}
// 等价于
fn read_file_long() -> Result<String, io::Error> {
let mut f = match File::open("hello.txt") {
Ok(file) => file,
Err(e) => return Err(e),
};
let mut s = String::new();
match f.read_to_string(&mut s) {
Ok(_) => Ok(s),
Err(e) => Err(e),
}
}
5. Option
标准解释:表示可能存在或不存在的值的枚举,Some(T) 表示有值,None 表示无值。
易懂解释:一个盒子,可能有东西,也可能是空的。比 null 更安全。
fn find_word(text: &str, word: &str) -> Option<usize> {
text.find(word)
}
let position = find_word("hello world", "world");
match position {
Some(index) => println!("找到,位置在 {}", index),
None => println!("没找到"),
}
// 常用方法
let x: Option<i32> = Some(5);
x.unwrap(); // 获取值,None 则 panic
x.unwrap_or(0); // 获取值,None 则返回 0
x.map(|v| v * 2); // 转换内部的值
x.and_then(|v| Some(v + 1)); // 链式操作
八、Trait 特质
1. Trait (特质)
标准解释:定义共享行为的抽象机制,类似其他语言的接口。
易懂解释:定义一组"能力"的清单。类型实现了某个 trait,就说明它具备这些能力。
// 定义 trait
trait Summary {
fn summarize(&self) -> String;
// 默认实现
fn author(&self) -> String {
String::from("Unknown")
}
}
// 为类型实现 trait
struct Article {
title: String,
content: String,
}
impl Summary for Article {
fn summarize(&self) -> String {
format!("{}: {}", self.title, self.content)
}
}
2. Trait Bound (Trait 约束)
标准解释:限制泛型类型必须实现某些 trait。
易懂解释:给泛型加限制条件,要求类型必须具备某些能力。
// 泛型约束
fn print_summary<T: Summary>(item: &T) {
println!("{}", item.summarize());
}
// 多重约束
fn print_debug_summary<T: Summary + std::fmt::Debug>(item: &T) {
println!("{:?}", item);
println!("{}", item.summarize());
}
// where 子句(更清晰的写法)
fn some_function<T, U>(t: &T, u: &U) -> i32
where
T: Display + Clone,
U: Clone + Debug,
{
// ...
}
3. Trait Object (Trait 对象)
标准解释:使用 dyn Trait 语法创建的动态分发类型,允许在运行时处理不同具体类型。
易懂解释:把不同类型"装进"同一个容器里,运行时才知道具体是什么类型。
trait Shape {
fn area(&self) -> f64;
}
struct Circle { radius: f64 }
struct Rectangle { width: f64, height: f64 }
impl Shape for Circle {
fn area(&self) -> f64 { 3.14 * self.radius * self.radius }
}
impl Shape for Rectangle {
fn area(&self) -> f64 { self.width * self.height }
}
// 使用 trait 对象
let shapes: Vec<Box<dyn Shape>> = vec![
Box::new(Circle { radius: 1.0 }),
Box::new(Rectangle { width: 2.0, height: 3.0 }),
];
for shape in shapes {
println!("面积: {}", shape.area());
}
4. 静态分发 vs 动态分发
标准解释:
- 静态分发:编译时确定调用哪个方法实现(泛型 + trait bound)
- 动态分发:运行时确定调用哪个方法实现(trait 对象)
易懂解释:
- 静态分发:编译时就决定了用哪个,像提前订好餐厅
- 动态分发:运行时才决定用哪个,像到现场再选餐厅
// 静态分发(编译时确定)
fn static_dispatch<T: Shape>(shape: &T) {
shape.area(); // 编译时就知道调用哪个实现
}
// 动态分发(运行时确定)
fn dynamic_dispatch(shape: &dyn Shape) {
shape.area(); // 运行时查找 vtable 确定调用
}
5. 标记 Trait (Marker Trait)
标准解释:没有方法的 trait,用于标记类型具有某些属性。
易懂解释:给类型贴个标签,说明它有某种特性。
// 内置标记 trait
// Send: 类型可以安全地在线程间传递
// Sync: 类型可以安全地在线程间共享引用
// Copy: 类型可以通过位复制
// Sized: 类型在编译时已知大小
6. 关联类型 (Associated Type)
标准解释:在 trait 定义中指定的占位类型,由实现者指定具体类型。
易懂解释:trait 中说"我需要一个类型,但具体是什么由实现者决定"。
trait Container {
type Item; // 关联类型
fn get(&self) -> Option<&Self::Item>;
fn put(&mut self, item: Self::Item);
}
struct VecContainer<T> {
data: Vec<T>,
}
impl<T> Container for VecContainer<T> {
type Item = T; // 指定关联类型
fn get(&self) -> Option<&Self::Item> {
self.data.last()
}
fn put(&mut self, item: Self::Item) {
self.data.push(item);
}
}
7. 默认实现 (Default Implementation)
标准解释:trait 方法可以有默认实现,实现者可以选择使用默认实现或覆盖它。
易懂解释:trait 方法可以有"默认答案",实现者直接用或自己改。
trait Greet {
fn greet(&self) -> String {
String::from("你好!") // 默认实现
}
}
struct Person { name: String }
impl Greet for Person {
// 不实现 greet,使用默认
}
struct Formal { name: String }
impl Greet for Formal {
fn greet(&self) -> String {
format!("尊敬的 {},您好!", self.name) // 覆盖默认
}
}
8. Supertrait (父 Trait)
标准解释:一个 trait 可以要求实现它的类型同时实现另一个 trait。
易懂解释:trait 可以继承其他 trait,要求具备更多能力。
trait Animal {
fn name(&self) -> String;
}
// Dog 要求实现 Animal(父 trait)
trait Dog: Animal {
fn bark(&self) {
println!("{} 说:汪汪!", self.name());
}
}
struct MyDog { name: String }
impl Animal for MyDog {
fn name(&self) -> String {
self.name.clone()
}
}
impl Dog for MyDog {
// 自动获得 bark 方法
}
九、泛型
1. 泛型 (Generics)
标准解释:编写适用于多种类型的代码,使用 <T> 等类型参数。
易懂解释:写代码时留个"空位",用的时候再填具体类型。像模板一样。
// 泛型函数
fn largest<T: PartialOrd>(list: &[T]) -> &T {
let mut largest = &list[0];
for item in list {
if item > largest {
largest = item;
}
}
largest
}
// 泛型结构体
struct Point<T> {
x: T,
y: T,
}
// 多类型参数
struct Point2<T, U> {
x: T,
y: U,
}
// 泛型枚举
enum Option<T> {
Some(T),
None,
}
enum Result<T, E> {
Ok(T),
Err(E),
}
2. 泛型约束 (Generic Constraints)
标准解释:限制泛型类型参数必须满足的条件。
易懂解释:给泛型加限制,不是什么类型都能用。
// 单个约束
fn print_it<T: Display>(value: T) {
println!("{}", value);
}
// 多个约束
fn process<T: Display + Clone>(value: T) {
let cloned = value.clone();
println!("{} and {}", value, cloned);
}
// where 子句
fn complex<T, U>(t: T, u: U) -> i32
where
T: Display + Clone,
U: Clone + Debug,
{
0
}
3. 泛型实现
标准解释:为泛型类型实现方法。
易懂解释:给模板类型添加功能。
struct Point<T> {
x: T,
y: T,
}
// 为所有 Point<T> 实现
impl<T> Point<T> {
fn x(&self) -> &T {
&self.x
}
}
// 为特定类型实现(只有 f64 才有这个方法)
impl Point<f64> {
fn distance_from_origin(&self) -> f64 {
(self.x.powi(2) + self.y.powi(2)).sqrt()
}
}
4. 单态化 (Monomorphization)
标准解释:编译时将泛型代码展开为具体类型代码的过程。
易懂解释:编译器把泛型代码复制多份,每份填入不同类型。这就是为什么泛型没有运行时开销。
// 泛型代码
fn add<T: Add<Output = T>>(a: T, b: T) -> T {
a + b
}
// 编译器展开(单态化)后:
fn add_i32(a: i32, b: i32) -> i32 { a + b }
fn add_f64(a: f64, b: f64) -> f64 { a + b }
十、智能指针
1. Box
标准解释:堆分配的智能指针,用于在堆上存储数据。
易懂解释:把数据放到堆上,栈上只留一个指针。就像把贵重物品存银行保险箱,手里只留钥匙。
// 在堆上存储
let b = Box::new(5);
println!("b = {}", b);
// 递归类型必须用 Box
enum List {
Cons(i32, Box<List>),
Nil,
}
2. Rc (Reference Counting)
标准解释:引用计数智能指针,允许多个所有者共享同一数据。用于单线程场景。
易懂解释:多个变量可以共同拥有一个数据,用计数器记录有多少人在用。最后一个人走的时候,数据才释放。
use std::rc::Rc;
let a = Rc::new(5);
let b = Rc::clone(&a); // 引用计数 +1
let c = Rc::clone(&a); // 引用计数 +1
println!("引用计数: {}", Rc::strong_count(&a)); // 3
3. Arc (Atomic Reference Counting)
标准解释:原子引用计数智能指针,线程安全版本的多所有权指针。
易懂解释:Rc 的线程安全版本,可以在多线程间共享数据。
use std::sync::Arc;
use std::thread;
let data = Arc::new(vec![1, 2, 3]);
for _ in 0..3 {
let data = Arc::clone(&data);
thread::spawn(move || {
println!("{:?}", data);
});
}
4. RefCell
标准解释:内部可变性模式,允许在不可变引用的情况下修改内部数据。运行时检查借用规则。
易懂解释:表面上是不可变的,但里面可以偷偷改。借用规则在运行时检查而不是编译时。
use std::cell::RefCell;
let data = RefCell::new(5);
// 借用可变引用
*data.borrow_mut() += 1;
// 借用不可变引用
println!("{}", data.borrow());
// 运行时检查借用规则
let ref1 = data.borrow();
let ref2 = data.borrow(); // OK:多个不可变借用
// let ref3 = data.borrow_mut(); // 运行时 panic!已有不可变借用
5. Mutex
标准解释:互斥锁,确保同一时刻只有一个线程可以访问数据。
易懂解释:一把锁,同一时间只能有一个人用。用完要解锁。
use std::sync::{Arc, Mutex};
use std::thread;
let data = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let data = Arc::clone(&data);
let handle = thread::spawn(move || {
let mut num = data.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("结果: {}", *data.lock().unwrap()); // 10
6. RwLock
标准解释:读写锁,允许多个读者或一个写者。
易懂解释:比 Mutex 更灵活。可以多个人同时读,但写的时候只能一个人。
use std::sync::RwLock;
let lock = RwLock::new(5);
// 多个读锁可以共存
let r1 = lock.read().unwrap();
let r2 = lock.read().unwrap();
println!("{} {}", r1, r2);
drop(r1);
drop(r2);
// 写锁独占
let mut w = lock.write().unwrap();
*w += 1;
7. Cow (Copy on Write)
标准解释:写时复制的智能指针,允许借用或拥有的数据。
易懂解释:能借就借,需要改的时候再复制一份。
use std::borrow::Cow;
fn modify_if_needed(input: &str) -> Cow<str> {
if input.contains("bad") {
// 需要修改,返回 Owned
Cow::Owned(input.replace("bad", "good"))
} else {
// 不需要修改,返回 Borrowed
Cow::Borrowed(input)
}
}
let s1 = modify_if_needed("hello"); // Borrowed
let s2 = modify_if_needed("bad world"); // Owned
8. Deref 和 DerefMut Trait
标准解释:允许智能指针像常规引用一样行为。
易懂解释:让智能指针能用 * 解引用,自动转换类型。
use std::ops::Deref;
struct MyBox<T>(T);
impl<T> MyBox<T> {
fn new(x: T) -> MyBox<T> {
MyBox(x)
}
}
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
let x = MyBox::new(5);
assert_eq!(*x, 5); // 解引用
// Deref 强制转换
fn hello(name: &str) {
println!("Hello, {}!", name);
}
let m = MyBox::new(String::from("Rust"));
hello(&m); // 自动从 &MyBox<String> 转换为 &str
9. Drop Trait
标准解释:定义值离开作用域时的清理行为。
易懂解释:自定义"临终遗言",变量销毁时自动执行。
struct CustomPointer {
data: String,
}
impl Drop for CustomPointer {
fn drop(&mut self) {
println!("释放: {}", self.data);
}
}
{
let p = CustomPointer { data: String::from("test") };
} // 离开作用域,自动调用 drop,打印 "释放: test"
十一、并发编程
1. 线程 (Thread)
标准解释:使用 std::thread::spawn 创建的并发执行单元。
易懂解释:让程序同时做多件事,每个线程是一条执行路径。
use std::thread;
use std::time::Duration;
thread::spawn(|| {
for i in 1..10 {
println!("子线程: {}", i);
thread::sleep(Duration::from_millis(1));
}
});
for i in 1..5 {
println!("主线程: {}", i);
thread::sleep(Duration::from_millis(1));
}
2. JoinHandle
标准解释:线程句柄,用于等待线程完成。
易懂解释:拿到线程的"把手",可以等待线程结束。
use std::thread;
let handle = thread::spawn(|| {
println!("子线程执行");
42
});
let result = handle.join().unwrap(); // 等待并获取返回值
println!("返回值: {}", result);
3. 消息传递 (Message Passing)
标准解释:使用通道(channel)在线程间传递消息。
易懂解释:线程间通过"管道"发消息交流,一个发一个收。
use std::sync::mpsc; // multiple producer, single consumer
use std::thread;
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let val = String::from("你好");
tx.send(val).unwrap();
});
let received = rx.recv().unwrap();
println!("收到: {}", received);
4. Send Trait
标准解释:标记 trait,表示类型可以安全地在线程间转移所有权。
易懂解释:类型可以"搬家"到另一个线程。
// 大多数类型自动实现 Send
// Rc<T> 不是 Send,Arc<T> 是 Send
5. Sync Trait
标准解释:标记 trait,表示类型可以安全地在线程间共享引用(&T 是 Send 的)。
易懂解释:多个线程可以同时持有这个类型的引用。
// 如果 &T 是 Send,那么 T 是 Sync
// RefCell<T> 不是 Sync,Mutex<T> 是 Sync
6. 原子类型 (Atomic Types)
标准解释:std::sync::atomic 模块中的类型,提供原子操作。
易懂解释:操作不会被中断的基本类型,适合高并发场景。
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::Arc;
use std::thread;
let counter = Arc::new(AtomicU32::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
handles.push(thread::spawn(move || {
counter.fetch_add(1, Ordering::SeqCst);
}));
}
for h in handles {
h.join().unwrap();
}
println!("计数: {}", counter.load(Ordering::SeqCst));
7. 内存顺序 (Memory Ordering)
标准解释:定义原子操作在多线程环境中的可见性顺序。
易懂解释:告诉编译器和 CPU 如何安排操作的顺序。
| 顺序 | 说明 | 性能 | 安全性 |
|---|---|---|---|
| Relaxed | 最小保证,只保证原子性 | 最高 | 最低 |
| Release | 写操作,之前的操作不会被重排到后面 | 中等 | 中等 |
| Acquire | 读操作,之后的操作不会被重排到前面 | 中等 | 中等 |
| SeqCst | 完全顺序一致 | 最低 | 最高 |
十二、异步编程
1. async/await
标准解释:Rust 的异步编程语法,async 定义异步代码块,await 等待异步操作完成。
易懂解释:写异步代码像同步代码一样。async 标记这是异步操作,await 等待结果。
// 需要 async 运行时(如 tokio)
async fn say_hello() {
println!("hello");
}
async fn get_data() -> String {
// 模拟异步操作
String::from("data")
}
async fn process() {
say_hello().await;
let data = get_data().await;
println!("{}", data);
}
2. Future
标准解释:表示可能还没完成的异步计算。
易懂解释:一个"承诺",以后会给你结果。
use std::future::Future;
// Future trait 定义
pub trait Future {
type Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
}
pub enum Poll<T> {
Ready(T),
Pending,
}
3. 异步运行时 (Async Runtime)
标准解释:执行异步代码的环境,如 tokio、async-std。
易懂解释:异步代码需要有人来"驱动"执行,运行时就是这个司机。
// tokio 运行时示例
#[tokio::main]
async fn main() {
println!("hello");
}
// 等价于
fn main() {
tokio::runtime::Runtime::new()
.block_on(async {
println!("hello");
});
}
4. Pin 和 Unpin
标准解释:
Pin<P>:防止被指向的值在内存中移动Unpin:表示类型可以安全移动
易懂解释:Pin 把值"钉"在内存某个位置不动,用于自引用结构。
use std::pin::Pin;
// 大多数类型自动实现 Unpin
// 自引用结构需要 !Unpin
fn use_pin() {
let mut boxed = Box::pin(5);
let pinned: Pin<&mut i32> = boxed.as_mut();
// pinned 不能移动
}
5. 异步函数与异步代码块
标准解释:async fn 定义返回 Future 的函数,async {} 创建 Future 代码块。
易懂解释:两种写异步代码的方式。
// 异步函数
async fn add(a: i32, b: i32) -> i32 {
a + b
}
// 异步代码块
let future = async {
let result = add(1, 2).await;
result * 2
};
6. 并发执行 (Concurrent Execution)
标准解释:使用 join!、select! 等宏同时运行多个 Future。
易懂解释:同时跑多个异步任务,不是一个个排队。
use tokio::join;
async fn task1() -> i32 { 1 }
async fn task2() -> i32 { 2 }
async fn run() {
// 并发执行,等待所有完成
let (r1, r2) = join!(task1(), task2());
println!("{} {}", r1, r2);
}
use tokio::select;
async fn run_select() {
// 竞争执行,返回最先完成的
let result = select! {
r1 = task1() => r1,
r2 = task2() => r2,
};
println!("{}", result);
}
十三、宏系统
1. 宏 (Macro)
标准解释:Rust 的元编程机制,在编译时生成代码。
易懂解释:写代码的代码。编译前先"展开"成真正的代码。
2. 声明式宏 (Declarative Macros)
标准解释:使用 macro_rules! 定义的宏,通过模式匹配生成代码。
易懂解释:像 match 一样匹配模式,然后替换成对应的代码。
// 简化的 vec! 宏
macro_rules! my_vec {
( $( $x:expr ),* ) => {
{
let mut temp_vec = Vec::new();
$(
temp_vec.push($x);
)*
temp_vec
}
};
}
let v = my_vec![1, 2, 3];
3. 过程宏 (Procedural Macros)
标准解释:使用 Rust 代码操作 TokenStream 的宏,更强大但更复杂。
易懂解释:用代码来生成代码,可以读取和修改代码结构。
三种类型:
- 派生宏 (Derive Macro):
#[derive(Debug)] - 属性宏 (Attribute Macro):
#[route(GET, "/")] - 函数式宏 (Function-like Macro):
sql!(SELECT * FROM users)
// 派生宏示例(需要单独的 crate)
use proc_macro::TokenStream;
use quote::quote;
use syn;
#[proc_macro_derive(HelloMacro)]
pub fn hello_macro_derive(input: TokenStream) -> TokenStream {
let ast = syn::parse(input).unwrap();
impl_hello_macro(&ast)
}
fn impl_hello_macro(ast: &syn::DeriveInput) -> TokenStream {
let name = &ast.ident;
let gen = quote! {
impl HelloMacro for #name {
fn hello_macro() {
println!("Hello, Macro! My name is {}!", stringify!(#name));
}
}
};
gen.into()
}
4. 宏的卫生性 (Macro Hygiene)
标准解释:宏中定义的变量不会与宏外部的变量冲突。
易懂解释:宏里的变量"自带结界",不会和外部的变量搞混。
macro_rules! using_x {
($x:expr) => {
{
let x = 10; // 宏内部的 x
$x // 参数,不是 x
}
};
}
let x = 5;
let result = using_x!(x + 1); // 5 + 1 = 6,不是 10 + 1
5. 常用内置宏
| 宏 | 用途 |
|---|---|
println! |
格式化打印 |
format! |
格式化字符串 |
vec! |
创建 Vec |
panic! |
触发 panic |
assert! |
断言 |
assert_eq! |
相等断言 |
dbg! |
调试打印 |
todo! |
标记未完成代码 |
unimplemented! |
标记未实现代码 |
compile_error! |
编译时报错 |
十四、模块系统
1. 模块 (Module)
标准解释:使用 mod 关键字定义的代码组织单元。
易懂解释:把代码分类整理的盒子,相关的东西放一起。
// 内联模块
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
// 引用其他文件
mod math; // 引用 math.rs 或 math/mod.rs
2. 可见性 (Visibility)
标准解释:控制项能否被其他模块访问的属性。
易懂解释:设置谁能看到、谁能用。
| 关键字 | 范围 |
|---|---|
pub |
公开,任何地方可访问 |
pub(crate) |
仅当前 crate 可访问 |
pub(super) |
仅父模块可访问 |
pub(self) |
仅当前模块可访问 |
pub(in path) |
指定路径可访问 |
| 无(默认) | 私有,仅当前模块可访问 |
mod outer {
pub fn public() {}
fn private() {}
pub mod inner {
pub fn inner_public() {}
pub(crate) fn crate_only() {}
pub(super) fn parent_only() {}
}
}
3. use 关键字
标准解释:将路径引入当前作用域。
易懂解释:创建快捷方式,不用写长路径。
use std::collections::HashMap;
use std::io::{self, Read, Write}; // 多个项
use std::collections::*; // 所有公开项(谨慎使用)
use std::collections::HashMap as Map; // 重命名
4. 路径 (Path)
标准解释:引用模块中项的方式,分为绝对路径和相对路径。
易懂解释:告诉编译器东西在哪的"地址"。
// 绝对路径:从 crate 根开始
crate::front_of_house::hosting::add_to_waitlist();
// 相对路径:从当前模块开始
front_of_house::hosting::add_to_waitlist();
// super:父模块
super::some_function();
// self:当前模块
self::inner_function();
5. 文件组织
标准解释:Rust 的模块可以放在单独的文件中。
易懂解释:大项目代码太多,分文件存放。
项目结构:
src/
├── main.rs
├── lib.rs # 库根
├── config.rs # config 模块
└── network/ # network 模块目录
├── mod.rs # 模块声明
├── client.rs # client 子模块
└── server.rs # server 子模块
// main.rs 或 lib.rs
mod config;
mod network;
// network/mod.rs
pub mod client;
pub mod server;
十五、Unsafe Rust
1. Unsafe 块
标准解释:使用 unsafe 关键字标记可以执行危险操作的代码块。
易懂解释:告诉编译器"我知道我在干什么,别管我",可以做一些平时不允许的操作。
unsafe {
// 解引用裸指针
// 调用 unsafe 函数
// 访问可变静态变量
// 实现 unsafe trait
// 访问 union 字段
}
2. 裸指针 (Raw Pointer)
标准解释:不保证安全性的指针类型 *const T 和 *mut T。
易懂解释:最原始的指针,没有借用规则保护,需要自己保证安全。
let mut num = 5;
let r1 = &num as *const i32; // 不可变裸指针
let r2 = &mut num as *mut i32; // 可变裸指针
unsafe {
println!("r1 = {}", *r1);
println!("r2 = {}", *r2);
}
3. Unsafe 函数
标准解释:使用 unsafe fn 声明的函数,调用时必须放在 unsafe 块中。
易懂解释:危险函数,调用者需要自己保证安全。
unsafe fn dangerous() {
// 危险操作
}
unsafe {
dangerous();
}
4. Unsafe Trait
标准解释:使用 unsafe trait 声明的 trait,实现时需要 unsafe impl。
易懂解释:告诉实现者"你需要保证某些安全条件"。
unsafe trait SafeToTransfer {}
unsafe impl SafeToTransfer for MyType {}
// 使用
fn transfer<T: SafeToTransfer>(data: T) {
// ...
}
5. 可变静态变量
标准解释:使用 static mut 声明的全局可变变量,访问需要 unsafe。
易懂解释:全局可变变量,任何地方都能改,容易出问题。
static mut COUNTER: u32 = 0;
unsafe fn add_to_count(inc: u32) {
COUNTER += inc;
}
6. 外部函数接口 (FFI)
标准解释:Rust 与其他语言(如 C)交互的机制。
易懂解释:调用其他语言写的函数,或让其他语言调用 Rust。
// 调用 C 函数
extern "C" {
fn abs(input: i32) -> i32;
}
unsafe {
println!("绝对值: {}", abs(-3));
}
// 让 C 调用 Rust 函数
#[no_mangle]
pub extern "C" fn call_from_c() {
println!("从 C 调用!");
}
十六、高级特性
1. 类型状态模式 (Type State Pattern)
标准解释:使用类型系统在编译时保证状态转换的正确性。
易懂解释:用不同的类型代表不同状态,编译器帮你检查状态转换对不对。
use std::marker::PhantomData;
struct Unconnected;
struct Connected;
struct Connection<State> {
address: String,
_state: PhantomData<State>,
}
impl Connection<Unconnected> {
fn connect(self) -> Connection<Connected> {
Connection {
address: self.address,
_state: PhantomData,
}
}
}
impl Connection<Connected> {
fn send(&self, data: &str) {
println!("发送到 {}: {}", self.address, data);
}
}
// 编译时保证状态正确
let conn = Connection::<Unconnected> { address: "127.0.0.1".into(), _state: PhantomData };
// conn.send("hello"); // 编译错误!未连接
let conn = conn.connect();
conn.send("hello"); // OK
2. Builder 模式
标准解释:使用链式调用构建复杂对象的模式。
易懂解释:一步一步配置对象,像搭积木一样。
#[derive(Debug)]
struct ServerConfig {
host: String,
port: u16,
ssl: bool,
}
impl ServerConfig {
fn builder() -> ServerConfigBuilder {
ServerConfigBuilder::default()
}
}
#[derive(Default)]
struct ServerConfigBuilder {
host: String,
port: u16,
ssl: bool,
}
impl ServerConfigBuilder {
fn host(mut self, host: impl Into<String>) -> Self {
self.host = host.into();
self
}
fn port(mut self, port: u16) -> Self {
self.port = port;
self
}
fn ssl(mut self, ssl: bool) -> Self {
self.ssl = ssl;
self
}
fn build(self) -> ServerConfig {
ServerConfig {
host: self.host,
port: self.port,
ssl: self.ssl,
}
}
}
let config = ServerConfig::builder()
.host("example.com")
.port(443)
.ssl(true)
.build();
3. 迭代器 (Iterator)
标准解释:实现 Iterator trait 的类型,提供遍历序列的能力。
易懂解释:一个能依次吐出元素的"管道"。
pub trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
// 许多默认方法...
}
// 自定义迭代器
struct Counter {
count: usize,
max: usize,
}
impl Counter {
fn new(max: usize) -> Self {
Self { count: 0, max }
}
}
impl Iterator for Counter {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
if self.count < self.max {
self.count += 1;
Some(self.count)
} else {
None
}
}
}
// 使用
for i in Counter::new(5) {
println!("{}", i); // 1, 2, 3, 4, 5
}
4. 迭代器适配器
标准解释:返回新迭代器的方法,用于转换或过滤序列。
易懂解释:把一个迭代器变成另一个迭代器。
| 方法 | 用途 |
|---|---|
map |
转换每个元素 |
filter |
过滤元素 |
filter_map |
过滤并转换 |
take |
取前 n 个 |
skip |
跳过前 n 个 |
chain |
连接两个迭代器 |
zip |
配对两个迭代器 |
enumerate |
添加索引 |
flatten |
展平嵌套 |
flat_map |
展平并转换 |
inspect |
检查不修改 |
rev |
反转 |
let v: Vec<i32> = (1..=10)
.filter(|x| x % 2 == 0) // 2, 4, 6, 8, 10
.map(|x| x * x) // 4, 16, 36, 64, 100
.take(3) // 4, 16, 36
.collect();
5. 消费适配器
标准解释:消费迭代器并产生最终结果的方法。
易懂解释:把迭代器的元素"吃完",给出结果。
| 方法 | 用途 |
|---|---|
collect |
收集成集合 |
sum |
求和 |
product |
求积 |
count |
计数 |
max/min |
最大/最小值 |
find |
查找元素 |
position |
查找位置 |
any/all |
检查条件 |
fold |
折叠/归约 |
for_each |
对每个执行操作 |
let sum: i32 = (1..=10).sum(); // 55
let v: Vec<i32> = (1..=5).collect(); // [1, 2, 3, 4, 5]
let has_even = (1..=10).any(|x| x % 2 == 0); // true
let product = (1..=5).fold(1, |acc, x| acc * x); // 120
6. 闭包 (Closure)
标准解释:可以捕获环境的匿名函数。
易懂解释:一个能记住周围变量的"小函数"。
// 闭包语法
let add = |a, b| a + b;
let add = |a: i32, b: i32| -> i32 { a + b };
// 捕获环境变量
let x = 10;
let add_x = |a| a + x; // 捕获 x
// 三种捕获方式
let mut s = String::from("hello");
// FnOnce: 获取所有权
let consume = move || {
let _ = s; // s 被移动
};
// FnMut: 可变借用
let mut modify = || {
s.push_str(" world");
};
// Fn: 不可变借用
let read = || {
println!("{}", s);
};
7. 高阶函数
标准解释:接受或返回函数的函数。
易懂解释:函数可以当参数传,也可以当返回值。
// 函数作为参数
fn apply<F>(f: F, x: i32) -> i32
where
F: Fn(i32) -> i32,
{
f(x)
}
let double = |x| x * 2;
println!("{}", apply(double, 5)); // 10
// 返回闭包
fn make_adder(x: i32) -> impl Fn(i32) -> i32 {
move |y| x + y
}
let add_5 = make_adder(5);
println!("{}", add_5(3)); // 8
8. 操作符重载
标准解释:通过实现特定 trait 自定义操作符行为。
易懂解释:给自己的类型定义加减乘除等操作。
use std::ops::{Add, Sub, Mul};
#[derive(Debug, Clone, Copy, PartialEq)]
struct Point {
x: i32,
y: i32,
}
impl Add for Point {
type Output = Point;
fn add(self, other: Point) -> Point {
Point {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
let p1 = Point { x: 1, y: 2 };
let p2 = Point { x: 3, y: 4 };
let p3 = p1 + p2; // Point { x: 4, y: 6 }
9. From/Into Trait
标准解释:用于类型间转换的 trait。
易懂解释:定义怎么从一种类型变成另一种类型。
struct Celsius(f64);
struct Fahrenheit(f64);
impl From<Fahrenheit> for Celsius {
fn from(f: Fahrenheit) -> Self {
Celsius((f.0 - 32.0) * 5.0 / 9.0)
}
}
impl From<Celsius> for Fahrenheit {
fn from(c: Celsius) -> Self {
Fahrenheit(c.0 * 9.0 / 5.0 + 32.0)
}
}
let c = Celsius(0.0);
let f: Fahrenheit = c.into(); // 32.0
let c2 = Celsius::from(f); // 0.0
10. Default Trait
标准解释:提供默认值的 trait。
易懂解释:定义类型的"出厂设置"。
#[derive(Debug, Default)]
struct Config {
host: String,
port: u16,
debug: bool,
}
impl Default for Config {
fn default() -> Self {
Self {
host: String::from("localhost"),
port: 8080,
debug: false,
}
}
}
let config = Config::default();
// 或使用 ..Default::default()
let custom = Config {
port: 3000,
..Default::default()
};
11. Debug 和 Display Trait
标准解释:
Debug:用于调试的格式化输出,可通过#[derive(Debug)]自动实现Display:用于用户友好的格式化输出,需手动实现
易懂解释:
Debug:给开发者看的,详细但不一定美观Display:给用户看的,友好美观
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
impl std::fmt::Display for Point {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
let p = Point { x: 1, y: 2 };
println!("{:?}", p); // Debug: Point { x: 1, y: 2 }
println!("{}", p); // Display: (1, 2)
12. AsRef 和 AsMut Trait
标准解释:用于廉价引用转换的 trait。
易懂解释:把一种引用变成另一种引用,不花钱(不复制数据)。
let s = String::from("hello");
// AsRef 转换
let bytes: &[u8] = s.as_ref(); // &String -> &[u8]
let str_ref: &str = s.as_ref(); // &String -> &str
// 常用于函数参数
fn print_length<T: AsRef<str>>(s: T) {
println!("长度: {}", s.as_ref().len());
}
print_length("hello"); // &str
print_length(String::from("hello")); // String
13. Borrow 和 ToOwned Trait
标准解释:
Borrow:从拥有所有权的类型借用引用ToOwned:从引用创建拥有所有权的类型
易懂解释:
Borrow:借东西用ToOwned:把借的东西变成自己的
use std::borrow::{Borrow, ToOwned};
let s = String::from("hello");
let borrowed: &str = s.borrow(); // String -> &str
let owned: String = borrowed.to_owned(); // &str -> String
14. PhantomData
标准解释:零大小类型,用于标记类型参数的使用。
易懂解释:假装用了一个类型,但实际上不占用空间。
use std::marker::PhantomData;
struct HashMap<K, V> {
keys: Vec<K>,
values: Vec<V>,
_marker: PhantomData<(K, V)>, // 标记 K 和 V 被使用
}
15. Never Type (!)
标准解释:表示永不返回的类型,用于发散函数。
易懂解释:代表"永远不会发生",比如永远循环或总是 panic 的函数。
fn forever() -> ! { // 永不返回
loop {
// 永远循环
}
}
fn die() -> ! { // 总是 panic
panic!("bye");
}
// 在模式匹配中使用
let result = match option {
Some(v) => v,
None => return, // return 的类型是 !
};
16. 条件编译
标准解释:根据编译时条件决定是否编译某段代码。
易懂解释:告诉编译器什么情况下编译哪些代码。
// 根据操作系统
#[cfg(target_os = "linux")]
fn os_specific() {
println!("Linux");
}
#[cfg(target_os = "windows")]
fn os_specific() {
println!("Windows");
}
// 根据 feature
#[cfg(feature = "extra")]
fn extra_feature() {}
// 条件编译属性
#[cfg(debug_assertions)] // 仅在 debug 模式
fn debug_only() {}
// 条件导入
#[cfg(test)]
use testing_module::*;
17. 测试
标准解释:Rust 内置测试框架。
易懂解释:自动检查代码对不对。
// 单元测试
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(2 + 2, 4);
}
#[test]
#[should_panic] // 期望 panic
fn test_panic() {
panic!("expected");
}
#[test]
#[ignore] // 忽略这个测试
fn expensive_test() {
// 耗时测试
}
}
// 文档测试
/// 加法函数
///
/// # Examples
/// ```
/// let result = add(2, 3);
/// assert_eq!(result, 5);
/// ```
fn add(a: i32, b: i32) -> i32 {
a + b
}
// 运行测试
// cargo test
附录:术语速查表
| 中文 | 英文 | 简要说明 |
|---|---|---|
| 所有权 | Ownership | Rust 内存管理核心机制 |
| 借用 | Borrowing | 创建引用的行为 |
| 生命周期 | Lifetime | 引用有效的作用域 |
| 特质 | Trait | 定义共享行为 |
| 泛型 | Generics | 参数化类型 |
| 枚举 | Enum | 多变体类型 |
| 结构体 | Struct | 自定义数据类型 |
| 模式匹配 | Pattern Matching | 匹配数据结构 |
| 智能指针 | Smart Pointer | 智能管理内存的指针 |
| 闭包 | Closure | 捕获环境的匿名函数 |
| 迭代器 | Iterator | 遍历序列的类型 |
| 错误处理 | Error Handling | 处理程序错误 |
| 并发 | Concurrency | 多线程编程 |
| 异步 | Async | 非阻塞编程 |
| 宏 | Macro | 元编程机制 |
| 模块 | Module | 代码组织单元 |
| 不安全 | Unsafe | 跳过安全检查 |
本文档整理了 Rust 编程语言的核心术语概念,旨在帮助学习者更好地理解和使用 Rust。
浙公网安备 33010602011771号