1. Rust 简介与环境搭建
▼
什么是 Rust
Rust 是由 Mozilla 研究院的 Graydon Hoare 设计的系统级编程语言,首次发布于 2010 年,2015 年发布 1.0 稳定版。它专注于安全性、速度和并发性,解决了 C/C++ 中常见的内存安全问题,同时提供了零成本抽象。
- 内存安全:无垃圾回收机制,通过所有权系统保证内存安全
- 零成本抽象:高级抽象不牺牲运行时性能
- 并发无畏:编译期防止数据竞争
- 跨平台:支持编译到几乎所有主流操作系统
- 类型系统:强大的静态类型系统 + 类型推断
- 模式匹配:强大的控制流和数据结构分解能力
- 宏系统:元编程能力,可定义领域特定语言(DSL)
Rust 的应用场景
- 系统编程:操作系统、驱动、内核模块(Linux 内核已支持 Rust)
- Web 后端:Actix-web、Axum、Rocket、Warp 等高性能框架
- WebAssembly:编译为 WASM 在浏览器运行
- 命令行工具:ripgrep、bat、fd、exa 等替代传统工具
- 嵌入式系统:no_std 环境下的嵌入式开发
- 游戏开发:Bevy 引擎、游戏后端服务
- 区块链:Solana、Polkadot、Near 等项目大量使用 Rust
- DevOps 工具:Docker、Kubernetes 周边工具
- 桌面应用:Tauri 框架(比 Electron 更轻量)
安装 Rust
推荐使用官方工具 rustup 安装 Rust:
# Linux / macOS
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# 验证安装
rustc --version
cargo --version
rustup --version
# 更新 Rust
rustup update
# 安装特定版本
rustup install 1.75.0
rustup install stable
rustup install beta
rustup install nightly
# 切换默认版本
rustup default 1.75.0
rustup default stable
# 添加目标平台(交叉编译)
rustup target add wasm32-unknown-unknown
rustup target add x86_64-pc-windows-gnu
# 安装附加组件
rustup component add rust-src
rustup component add rustfmt
rustup component add clippy
rustup component add rust-analyzer
Windows 用户可从
https://rustup.rs
下载安装程序(需要 Microsoft C++ Build Tools),或使用 WSL2 安装 Linux 版本以获得最佳体验。
Hello World
创建你的第一个 Rust 程序:
// 手动编译运行
// 创建 main.rs
fn main() {
println!("Hello, World!");
}
// 编译运行:
// rustc main.rs
// ./main (或 main.exe)
// 使用 Cargo(推荐):
// cargo new hello_world
// cd hello_world
// cargo run
Cargo 项目结构
my_project/
├── Cargo.toml # 项目配置文件(类似 package.json)
├── Cargo.lock # 依赖锁定文件
├── src/
│ ├── main.rs # 二进制入口
│ ├── lib.rs # 库入口
│ └── bin/ # 多个二进制程序
│ └── other_main.rs
├── tests/ # 集成测试
│ └── integration.rs
├── benches/ # 性能基准测试
│ └── my_benchmark.rs
├── examples/ # 示例代码
│ └── example.rs
├── build.rs # 构建脚本
├── README.md
└── .gitignore
IDE 配置
推荐使用 VSCode + rust-analyzer 插件:
- rust-analyzer:官方推荐的 LSP 服务器,提供代码补全、跳转、类型提示
- Even Better TOML:TOML 语法高亮
- crates:显示依赖版本信息
- CodeLLDB:调试 Rust 程序
JetBrains CLion 也内置了强大的 Rust 支持(IntelliJ Rust 插件)。
Rust 版本(Edition)
Rust 每隔几年会发布一个新的 Edition,带来语法变化但不破坏兼容性:
- 2015 Edition:初始版本
- 2018 Edition:引入模块系统改进、async/await、? 运算符
- 2021 Edition:数组 IntoIterator、闭包捕获改进
- 2024 Edition:进一步简化语法和特性
# 在 Cargo.toml 中指定版本
[package]
edition = "2021" # 或 "2024"
# 使用 rustup 迁移
cargo fix --edition
cargo fix --edition-idioms
2. 变量与数据类型
▼
变量绑定
Rust 中变量默认是不可变的,使用 let 声明:
fn main() {
// 不可变变量
let x = 5;
// x = 6; // 编译错误!
// 可变变量
let mut y = 5;
y = 6; // OK
// 常量(必须标注类型,必须大写)
const MAX_POINTS: u32 = 100_000;
const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;
// Shadowing(变量遮蔽)
let x = 5;
let x = x + 1; // x 现在是 6
let x = x * 2; // x 现在是 12
let x = "hello"; // 可以改变类型
// 静态变量(有固定内存地址,可以是 mut)
static COUNTER: i32 = 0;
static mut MUTABLE_GLOBAL: i32 = 0; // 需要 unsafe 访问
}
const
vs
static
:
•
const
:编译时常量,可内联,无固定地址
•
static
:运行时静态变量,有固定地址,可用于 FFI
基本数据类型
Rust 是静态类型语言,主要标量类型:
整数类型
| 长度 | 有符号 | 无符号 | 范围 |
|---|---|---|---|
| 8-bit | i8 | u8 | -128 ~ 127 / 0 ~ 255 |
| 16-bit | i16 | u16 | -32768 ~ 32767 / 0 ~ 65535 |
| 32-bit | i32 | u32 | -2^31 ~ 2^31-1 |
| 64-bit | i64 | u64 | -2^63 ~ 2^63-1 |
| 128-bit | i128 | u128 | -2^127 ~ 2^127-1 |
| 架构 | isize | usize | 随指针大小变化 |
// 整数类型
let a: i8 = -128;
let b: u8 = 255;
let c: i32 = 1_000_000; // 默认 i32
let d: u64 = 42;
let e: isize = 10;
// 数字字面量
let decimal = 98_222; // 十进制
let hex = 0xff; // 十六进制
let octal = 0o77; // 八进制
let binary = 0b1111_0000; // 二进制
let byte = b'A'; // 字节 (u8)
// 整数方法
let x: i32 = -5;
let abs = x.abs(); // 5
let signum = x.signum(); // -1
let is_positive = x.is_positive();
let is_negative = x.is_negative();
let pow = 2i32.pow(10); // 1024
let sqrt = 16.0f64.sqrt(); // 4.0
let checked = 10u8.checked_add(20); // Some(30)
let overflow = 255u8.checked_add(1); // None
// 溢出检查
// debug 模式下整数溢出会 panic
// release 模式下会绕回
let (result, overflow) = 255u8.overflowing_add(1); // (0, true)
let wrapped = 255u8.wrapping_add(1); // 0
let saturated = 255u8.saturating_add(1); // 255
浮点类型
// 浮点类型
let f: f32 = 3.14;
let g: f64 = 3.1415926; // 默认 f64
// 特殊值
let inf = f64::INFINITY;
let neg_inf = f64::NEG_INFINITY;
let nan = f64::NAN;
let max = f64::MAX;
let min = f64::MIN;
let epsilon = f64::EPSILON;
// 判断特殊值
let is_nan = nan.is_nan();
let is_finite = 1.0.is_finite();
let is_infinite = inf.is_infinite();
// 浮点方法
let x: f64 = -3.7;
x.abs(); // 3.7
x.floor(); // -4.0
x.ceil(); // -3.0
x.round(); // -4.0
x.trunc(); // -3.0
x.fract(); // -0.7
x.sin(); // 正弦
x.cos(); // 余弦
x.ln(); // 自然对数
x.log2(); // 以 2 为底
x.log10(); // 以 10 为底
x.powi(2); // x^2
x.powf(2.5); // x^2.5
x.sqrt(); // 平方根
x.cbrt(); // 立方根
布尔与字符类型
// 布尔类型
let is_true: bool = true;
let is_false = 1 > 2;
// 字符类型(4 字节 Unicode 标量值)
let letter: char = 'A';
let emoji: char = '🦀';
let chinese: char = '中';
let accented: char = 'é';
// 字符方法
let c = 'A';
c.is_alphabetic(); // true
c.is_numeric(); // false
c.is_alphanumeric(); // true
c.is_whitespace(); // false
c.is_uppercase(); // true
c.is_lowercase(); // false
c.to_lowercase(); // 'a'
c.to_uppercase(); // 'A'
c.to_digit(16); // 转为数字
c.len_utf8(); // UTF-8 编码长度
c.len_utf16(); // UTF-16 编码长度
c.escape_unicode(); // Unicode 转义
复合类型
// 元组 (Tuple)
let tuple: (i32, f64, u8) = (500, 6.4, 1);
let (x, y, z) = tuple; // 解构
let first = tuple.0; // 索引访问
let second = tuple.1;
// 单元类型 (unit) - 空元组
let unit: () = ();
// 数组(固定长度,栈上分配)
let arr: [i32; 5] = [1, 2, 3, 4, 5];
let zeros = [0; 10]; // [0,0,0,0,0,0,0,0,0,0]
let first = arr[0];
let slice = &arr[1..3]; // &[2, 3]
// 数组方法
let arr = [1, 2, 3, 4, 5];
arr.len(); // 5
arr.contains(&3); // true
arr.iter().sum::<i32>(); // 15
arr.windows(2); // 滑动窗口 [1,2], [2,3]...
arr.chunks(2); // 分块
arr.sort(); // 排序 (需要 mut)
类型转换
use std::convert::TryInto;
fn main() {
let x: u32 = 10;
let y: i64 = x as i64; // as 关键字显式转换
let z: f64 = y as f64;
// 安全的类型转换
let big: u64 = 1000;
let small: u8 = big.try_into().unwrap();
// 字符串与数字互转
let num_str = "42";
let num: i32 = num_str.parse().unwrap();
let num: i32 = num_str.parse().unwrap_or(0);
let back = num.to_string();
// From / Into trait
let s: String = "hello".into();
let v: Vec<u8> = "hello".as_bytes().into();
}
使用
as
进行数值类型转换时,如果值超出目标类型范围,会发生截断而非报错。对于可能失败的场景,推荐使用
TryInto
、
TryFrom
或
checked_* / saturating_* / wrapping_*
方法。
3. 函数与控制流
▼
函数定义
// 基本函数
fn greet(name: &str) {
println!("Hello, {}!", name);
}
// 带返回值
fn add(a: i32, b: i32) -> i32 {
a + b // 最后一个表达式即为返回值(无分号)
}
// 多返回值
fn swap(a: i32, b: i32) -> (i32, i32) {
(b, a)
}
// 发散函数(永不返回)
fn crash() -> ! {
panic!("Boom!");
}
// 默认参数(Rust 不支持,使用 Option 或 builder 模式)
fn create_user(name: &str, age: Option<u32>) -> User {
User {
name: name.to_string(),
age: age.unwrap_or(18),
}
}
// 函数指针
fn apply(f: fn(i32) -> i32, x: i32) -> i32 {
f(x)
}
fn double(x: i32) -> i32 { x * 2 }
let result = apply(double, 5); // 10
// 外部函数(FFI)
extern "C" {
fn abs(input: i32) -> i32;
}
// const fn(编译期可计算)
const fn square(n: i32) -> i32 {
n * n
}
const SQUARE_FIVE: i32 = square(5);
// 内联函数
#[inline]
fn fast_add(a: i32, b: i32) -> i32 {
a + b
}
#[inline(always)] // 强制内联
fn always_inline() { }
#[inline(never)] // 禁止内联
fn never_inline() { }
表达式与语句
fn main() {
// 语句不返回值
let x = 5;
// 表达式有返回值
let y = {
let a = 3;
let b = 4;
a + b // 无分号,作为返回值
};
// 注意:加分号变为语句,返回 ()
let z = {
let val = 10;
val; // 有分号,z 是 ()
};
// return 关键字
fn early_return(x: i32) -> i32 {
if x < 0 {
return -1;
}
x
}
}
条件语句
fn main() {
let number = 7;
// if 表达式
if number < 5 {
println!("小于 5");
} else if number < 10 {
println!("小于 10");
} else {
println!("大于等于 10");
}
// if 作为表达式赋值
let result = if number % 2 == 0 {
"偶数"
} else {
"奇数"
};
// 条件链 (let else - Rust 1.65+)
let opt: Option<i32> = Some(42);
let Some(val) = opt else {
println!("不是 Some");
return;
};
println!("值是: {}", val);
// if let(简化单分支匹配)
if let Some(val) = opt {
println!("值是: {}", val);
}
// matches! 宏(判断是否符合模式)
let msg = Message::Quit;
if matches!(msg, Message::Quit) {
println!("Quit 消息");
}
}
循环
fn main() {
// loop(无限循环)
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2; // break 可返回值
}
};
// 循环标签
let mut count = 0;
'outer: loop {
let mut inner = 0;
loop {
if inner == 5 {
break 'outer; // 跳出外层循环
}
inner += 1;
}
count += 1;
}
// while 循环
let mut n = 3;
while n != 0 {
println!("{}!", n);
n -= 1;
}
// while let
let mut stack = vec![1, 2, 3];
while let Some(top) = stack.pop() {
println!("{}", top); // 3, 2, 1
}
// for 循环
for i in 0..5 {
println!("{}", i); // 0,1,2,3,4
}
for i in 0..=5 {
println!("{}", i); // 0,1,2,3,4,5
}
let arr = [10, 20, 30];
for (index, val) in arr.iter().enumerate() {
println!("[{}]: {}", index, val);
}
// 反向迭代
for i in (0..5).rev() {
println!("{}", i); // 4,3,2,1,0
}
// 步进
for i in (0..10).step_by(2) {
println!("{}", i); // 0,2,4,6,8
}
// break 和 continue
for i in 0..10 {
if i == 3 { continue; }
if i == 7 { break; }
println!("{}", i);
}
}
Match 表达式
fn describe_number(n: i32) -> &'static str {
match n {
1 => "一",
2 | 3 => "二或三",
4..=10 => "四到十",
x if x < 0 => "负数",
_ => "其他",
}
}
// 匹配守卫(match guard)
let pair = (2, -2);
match pair {
(x, y) if x + y == 0 => println!("互为相反数"),
_ => println!("不是"),
}
// @ 绑定
enum Message { Hello { id: i32 } }
let msg = Message::Hello { id: 5 };
match msg {
Message::Hello { id: id_variable @ 3..=7 } => {
println!("Found id in range: {}", id_variable);
}
Message::Hello { id } => println!("Found other id: {}", id),
}
4. 所有权与借用
▼
所有权规则
Rust 的核心特性,在编译时管理内存,无需垃圾回收:
- 每个值有且只有一个所有者(Owner)
- 同一时刻只能有一个所有者
- 当所有者离开作用域,值被丢弃(Drop)
- 任意时刻,要么只有一个可变引用,要么有多个不可变引用(不能同时存在)
- 引用必须始终有效(不能悬垂引用)
- 引用不能比其指向的数据活得更久
- 栈(Stack):固定大小的数据,LIFO 访问,速度快
- 堆(Heap):动态大小的数据,需要分配器管理,速度较慢
- 指向堆上数据的指针
- 长度(length)- 当前使用的字节数
- 容量(capacity)- 已分配的总字节数
Box<T>- 释放堆内存Vec<T>- 释放堆内存 + 递归 drop 元素String- 释放堆内存File- 关闭文件句柄Mutex<T>- 释放锁TcpStream- 关闭网络连接- 每个引用参数获得自己的生命周期参数
- 如果只有一个输入生命周期参数,它被赋给所有输出
- 如果有
&self或&mut self,self 的生命周期被赋给所有输出 - 解引用裸指针
- 调用 unsafe 函数或方法
- 访问或修改可变的静态变量
- 实现 unsafe trait
- 访问 union 的字段
- 只在必要时使用 unsafe
- 用 safe 抽象包裹 unsafe 代码
- 文档说明安全约束条件(# Safety 章节)
- 尽量缩小 unsafe 块的范围
- 提供安全的公共 API
- bindgen:自动生成 C 头文件的 Rust 绑定
- cbindgen:从 Rust 代码生成 C 头文件
- cc crate:在 build.rs 中编译 C/C++ 代码
- 优先使用迭代器而非手写循环(编译器可更好优化)
- 避免不必要的
clone(),使用引用或Cow - 使用
String::with_capacity()预分配 - 使用
Vec::with_capacity()避免重新分配 - 使用
rayon进行并行计算 - Profile 后再优化,避免过早优化
- 使用
Box<[T]>或Vec处理动态大小的集合 - 使用
smallveccrate 避免小集合的堆分配 - 使用
hashbrown或ahash替代默认 HashMap(更快) - 使用
parking_lot替代标准 Mutex(更快) - 使用
once_cell/LazyLock替代lazy_static - 避免在热路径上使用动态分发(
dyn Trait) - 使用
#[inline]内联关键函数 - 使用
likely()/unlikely()优化分支预测
fn main() {
// 栈上类型(Copy 语义)
let x = 5;
let y = x; // 复制,x 仍可用
println!("x={}, y={}", x, y);
// 堆上类型(Move 语义)
let s1 = String::from("hello");
let s2 = s1; // 移动所有权,s1 不再有效
// println!("{}", s1); // 编译错误!
println!("{}", s2);
// 克隆(深拷贝)
let s3 = s2.clone();
println!("s2={}, s3={}", s2, s3);
}
Copy vs Clone
// Copy trait:按位复制,隐式发生
// 实现了 Copy 的类型:所有整数、浮点、布尔、字符、仅含 Copy 类型的元组
// String、Vec 等堆上类型不实现 Copy
// Clone trait:显式调用 clone() 方法,深拷贝
let s1 = String::from("hello");
let s2 = s1.clone();
// 自定义类型实现 Copy
#[derive(Copy, Clone)]
struct Point {
x: i32,
y: i32,
}
// 注意:如果类型包含非 Copy 字段(如 String),则不能 derive Copy
// 但可以 derive Clone
函数与所有权
fn takes_ownership(s: String) {
println!("{}", s);
} // s 被 drop
fn makes_copy(n: i32) {
println!("{}", n);
}
fn gives_back(s: String) -> String {
s // 返回所有权
}
// 同时返回值和原值
fn calculate_length(s: String) -> (String, usize) {
let length = s.len();
(s, length)
}
fn main() {
let s = String::from("hello");
takes_ownership(s);
// s 不再有效
let n = 5;
makes_copy(n);
println!("{}", n); // OK,i32 是 Copy
let s2 = String::from("world");
let s3 = gives_back(s2);
println!("{}", s3);
}
引用与借用
// 不可变引用 &T
fn calculate_length(s: &String) -> usize {
s.len()
} // s 离开作用域,但不会 drop 因为不拥有
// 可变引用 &mut T
fn change(s: &mut String) {
s.push_str(", world");
}
fn main() {
let s = String::from("hello");
let len = calculate_length(&s);
println!("长度: {}", len);
let mut s = String::from("hello");
change(&mut s);
println!("{}", s);
// 借用规则
let mut s = String::from("hello");
let r1 = &s; // OK
let r2 = &s; // OK,多个不可变引用
// let r3 = &mut s; // 错误!存在不可变引用时不能有可变引用
println!("{} {}", r1, r2);
// r1, r2 不再使用
let r3 = &mut s; // OK,r1/r2 已不再使用
println!("{}", r3);
// Non-Lexical Lifetimes (NLL) - 2018 edition+
// 引用的生命周期在使用结束后立即结束,而非作用域结束
let mut s = String::from("hello");
let r1 = &s;
let r2 = &s;
println!("{} {}", r1, r2);
// r1, r2 在此之后不再使用
let r3 = &mut s; // OK!
println!("{}", r3);
}
借用检查规则:
切片(Slice)
fn first_word(s: &str) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
s
}
fn main() {
let mut s = String::from("hello world");
let word = first_word(&s);
println!("{}", word); // "hello"
// 字符串切片
let s = String::from("hello world");
let hello = &s[0..5]; // "hello"
let world = &s[6..11]; // "world"
let all = &s[..]; // "hello world"
// 数组切片
let arr = [1, 2, 3, 4, 5];
let slice: &[i32] = &arr[1..3];
// 切片方法
let s = &arr[1..4];
s.len(); // 3
s.is_empty(); // false
s.first(); // Some(&2)
s.last(); // Some(&4)
s.get(1); // Some(&3)
s.contains(&3); // true
s.starts_with(&[2]); // true
s.ends_with(&[4]); // true
s.split_at(1); // (&[2], &[3,4])
s.chunks(2); // 分块迭代
s.windows(2); // 滑动窗口
}
所有权与堆内存
理解堆和栈对于理解 Rust 的所有权至关重要:
String 由三部分组成(都在栈上):
let mut s = String::with_capacity(10);
s.push_str("hi");
println!("len: {}, cap: {}", s.len(), s.capacity()); // 2, 10
s.shrink_to_fit(); // 收缩容量到实际长度
s.reserve(20); // 预留额外空间
5. Deref 与 Drop Trait
▼
Deref Trait
Deref trait 允许智能指针像引用一样被使用,支持 Deref 强制转换:
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) -> &T {
&self.0
}
}
fn main() {
let x = 5;
let y = MyBox::new(x);
assert_eq!(5, x);
assert_eq!(5, *y); // * 操作符调用 deref()
// 实际上 *y 等价于 *(y.deref())
}
Deref 强制转换
编译器会自动在不同类型的引用之间进行转换:
fn hello(name: &str) {
println!("Hello, {}!", name);
}
fn main() {
let m = MyBox::new(String::from("Rust"));
// MyBox<String> --deref--> String --deref--> str
// &MyBox<String> --&--> &String --&--> &str
hello(&m); // 自动转换:&MyBox<String> -> &String -> &str
// 显式转换
let s: String = String::from("hello");
let slice: &str = &s; // String implements Deref<Target=str>
// Box<T> 同样支持
let b = Box::new(String::from("world"));
hello(&b); // 自动转换
}
DerefMut Trait
use std::ops::{Deref, DerefMut};
impl<T> DerefMut for MyBox<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}
Deref 强制转换规则:
•
&T
->
&U
当
T: Deref<Target=U>
•
&mut T
->
&mut U
当
T: DerefMut<Target=U>
•
&mut T
->
&U
当
T: Deref<Target=U>
(可变转不可变 OK)
• 反之不行(不可变不能转可变)
Drop Trait
Drop trait 允许在值离开作用域时执行自定义清理代码:
struct CustomSmartPointer {
name: String,
}
impl Drop for CustomSmartPointer {
fn drop(&mut self) {
println!("Dropping CustomSmartPointer with data `{}`!", self.name);
}
}
fn main() {
let c = CustomSmartPointer {
name: String::from("my stuff"),
};
let d = CustomSmartPointer {
name: String::from("other stuff"),
};
println!("CustomSmartPointers created.");
// 离开作用域时自动调用 drop,顺序与创建相反:d 先,c 后
}
提前释放 - std::mem::drop
fn main() {
let c = CustomSmartPointer {
name: String::from("some data"),
};
// 不能显式调用 drop() 方法(会 double drop)
// c.drop(); // 编译错误
// 使用 std::mem::drop 函数提前释放
drop(c); // 等价于 C++ 的析构函数提前调用
println!("CustomSmartPointer dropped before end of main.");
// c 不再可用
}
// std::mem::drop 的实现非常简单:
fn drop<T>(_x: T) {} // 通过所有权转移让编译器自动 drop
注意:
不能手动实现
Drop
的同时手动调用
drop
方法,这会导致 double-free。Rust 不允许显式调用
Drop::drop
方法,必须使用
std::mem::drop
。
常用 Drop 类型
6. 结构体与枚举
▼
结构体
// 经典结构体
struct User {
username: String,
email: String,
age: u32,
active: bool,
}
// 元组结构体
struct Color(u8, u8, u8);
struct Point(f64, f64, f64);
// 单元结构体
struct Marker;
// 带泛型的结构体
struct Wrapper<T> {
value: T,
}
// 带生命周期的结构体
struct Excerpt<'a> {
part: &'a str,
}
// 使用结构体
fn main() {
let mut user = User {
username: String::from("alice"),
email: String::from("alice@example.com"),
age: 30,
active: true,
};
user.age = 31;
// 字段初始化简写
let username = String::from("bob");
let email = String::from("bob@example.com");
let user2 = User { username, email, age: 25, active: true };
// 结构体更新语法
let user3 = User {
email: String::from("bob2@example.com"),
..user2 // 从 user2 拷贝其余字段(会移动所有权)
};
// 元组结构体
let red = Color(255, 0, 0);
println!("R={}, G={}, B={}", red.0, red.1, red.2);
// Newtype 模式(见设计模式章节)
struct Meters(f64);
struct Millimeters(f64);
}
方法(impl)
struct Rectangle {
width: f64,
height: f64,
}
impl Rectangle {
// 关联函数(类似静态方法,用 :: 调用)
fn new(width: f64, height: f64) -> Self {
Self { width, height }
}
fn square(size: f64) -> Self {
Self::new(size, size)
}
// 方法(取 &self)- 只读
fn area(&self) -> f64 {
self.width * self.height
}
fn is_square(&self) -> bool {
self.width == self.height
}
// 可变方法(取 &mut self)- 修改
fn resize(&mut self, width: f64, height: f64) {
self.width = width;
self.height = height;
}
// 消费方法(取 self)- 转移所有权
fn into_description(self) -> String {
format!("{}x{}", self.width, self.height)
}
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
}
// 可以有多个 impl 块
impl Rectangle {
fn perimeter(&self) -> f64 {
2.0 * (self.width + self.height)
}
}
fn main() {
let mut rect = Rectangle::new(5.0, 3.0);
println!("面积: {}", rect.area());
println!("周长: {}", rect.perimeter());
rect.resize(10.0, 4.0);
let desc = rect.into_description();
// rect 已被消费,不能再使用
}
自动引用与解引用:
调用方法时,Rust 会自动添加
&
、
&mut
或
*
,使得
rect.area()
和
(&rect).area()
等价。
枚举
// 基本枚举
enum Direction {
Up,
Down,
Left,
Right,
}
// 带数据的枚举
enum Message {
Quit, // 无数据
Move { x: i32, y: i32 }, // 结构体变体
Write(String), // 元组变体
ChangeColor(u8, u8, u8), // 多个值
Error { code: i32, msg: String },
}
// Option 和 Result 是标准库中最常用的枚举
enum Option<T> {
Some(T),
None,
}
enum Result<T, E> {
Ok(T),
Err(E),
}
impl Message {
fn call(&self) {
match self {
Message::Quit => println!("退出"),
Message::Move { x, y } => println!("移动到 ({}, {})", x, y),
Message::Write(text) => println!("消息: {}", text),
Message::ChangeColor(r, g, b) => {
println!("颜色: ({}, {}, {})", r, g, b);
}
Message::Error { code, msg } => {
println!("错误 {}: {}", code, msg);
}
}
}
}
fn main() {
let m = Message::Write(String::from("hello"));
m.call();
// Option 常用方法
let x: Option<i32> = Some(5);
x.is_some(); // true
x.is_none(); // false
x.unwrap(); // 5 (None 则 panic)
x.unwrap_or(0); // 5
x.unwrap_or_default(); // 5
x.unwrap_or_else(|| 0); // 5
x.map(|v| v * 2); // Some(10)
x.and_then(|v| Some(v * 2)); // Some(10)
x.filter(|v| *v > 3); // Some(5)
x.ok_or("empty"); // Ok(5)
// Option 组合
let opt1 = Some(2);
let opt2 = Some(3);
let sum = opt1.zip(opt2).map(|(a, b)| a + b); // Some(5)
}
7. 模式匹配
▼
Match 表达式
match 是 Rust 中最强大的控制流工具,要求穷举所有可能的值:
enum Coin {
Penny,
Nickel,
Dime,
Quarter(String),
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => {
println!("Lucky penny!");
1
}
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter(state) => {
println!("来自 {} 的 Quarter", state);
25
}
}
}
各种模式
fn match_examples() {
// 字面量匹配
let x = 3;
match x {
1 => println!("one"),
2 | 3 => println!("two or three"),
4..=10 => println!("four to ten"),
_ => println!("other"),
}
// 守卫(Guard)
let pair = (2, -2);
match pair {
(x, y) if x + y == 0 => println!("互为相反数"),
(x, y) => println!("不是相反数: {}, {}", x, y),
}
// 结构体匹配
struct Point { x: i32, y: i32, z: i32 }
let p = Point { x: 0, y: 7, z: 0 };
match p {
Point { x, y: 0, z: 0 } => println!("x 轴上: {}", x),
Point { x: 0, y, z: 0 } => println!("y 轴上: {}", y),
Point { x: 0, y: 0, z } => println!("z 轴上: {}", z),
Point { x, y, z } => println!("({}, {}, {})", x, y, z),
}
// 嵌套模式
enum Color { Rgb(u8, u8, u8), Hsv(u8, u8, u8) }
enum Message { Quit, Move { x: i32 }, ChangeColor(Color) }
let msg = Message::ChangeColor(Color::Rgb(255, 0, 0));
match msg {
Message::ChangeColor(Color::Rgb(r, g, b)) => {
println!("RGB: {}, {}, {}", r, g, b);
}
Message::ChangeColor(Color::Hsv(h, s, v)) => {
println!("HSV: {}, {}, {}", h, s, v);
}
_ => (),
}
// @ 绑定 - 匹配并同时绑定
enum Message { Hello { id: i32 } }
let msg = Message::Hello { id: 5 };
match msg {
Message::Hello { id: id_var @ 3..=7 } => {
println!("id 在范围内: {}", id_var);
}
Message::Hello { id } => println!("其他 id: {}", id),
}
// 忽略模式
let numbers = (2, 4, 8, 16, 32);
match numbers {
(first, _, third, _, fifth) => {
println!("{}, {}, {}", first, third, fifth);
}
}
// .. 忽略剩余部分
let p = Point { x: 1, y: 2, z: 3 };
match p {
Point { x, .. } => println!("x = {}", x),
}
// 解构结构体和元组
let Point { x, y, z } = p;
let (a, b, c, d, e) = numbers;
}
if let 和 while let
fn main() {
let config_max = Some(3u8);
// 只关心 Some 的情况(match 的简化)
if let Some(max) = config_max {
println!("最大值: {}", max);
} else {
println!("没有最大值");
}
// while let
let mut stack = vec![1, 2, 3];
while let Some(top) = stack.pop() {
println!("{}", top); // 3, 2, 1
}
// let else (Rust 1.65+) - 用于提前返回
fn get_first_char(s: &str) -> char {
let Some(c) = s.chars().next() else {
return '?'; // else 分支必须 diverge(返回/panic)
};
c
}
// matches! 宏 - 判断是否符合模式
let x = Some(5);
let is_some = matches!(x, Some(_));
let is_five = matches!(x, Some(5));
let is_even = matches!(x, Some(n) if n % 2 == 0);
// 在 filter 中使用
let v = vec![Some(1), None, Some(2), Some(3)];
let filtered: Vec<_> = v.iter().filter(|x| matches!(x, Some(_))).collect();
}
模式语法总结
| 模式 | 示例 | 说明 |
|---|---|---|
| 字面量 | 1, 'a', "hello" | 匹配具体值 |
| 范围 | 'a'..='z', 1..=10 | 匹配范围内 |
| 变量 | x, mut y | 绑定到变量 |
| 通配符 | _ | 忽略值 |
| 剩余 | .. | 忽略剩余字段 |
| 或 | 1 | 2 | 3 | 匹配任一值 |
| 守卫 | x if x > 0 | 附加条件 |
| 绑定 | x @ 1..=5 | 匹配并绑定 |
| 元组 | (a, b, c) | 解构元组 |
| 结构体 | Point { x, y } | 解构结构体 |
| 枚举 | Some(x), Ok(v) | 解构枚举 |
| 引用 | &x, &mut x | 匹配引用 |
8. 集合类型
▼
Vec<T> - 动态数组
fn main() {
// 创建
let v1: Vec<i32> = Vec::new();
let v2 = vec![1, 2, 3, 4, 5];
let v3 = vec![0; 5]; // [0,0,0,0,0]
let v4 = Vec::with_capacity(100); // 预分配容量
// 修改
let mut v = Vec::new();
v.push(1);
v.push(2);
v.push(3);
v.extend([4, 5, 6]); // 扩展
v.insert(0, 0); // 插入到索引
// 访问元素
let first = &v[0]; // 越界会 panic
let second = v.get(1); // 返回 Option
match v.get(10) {
Some(val) => println!("{}", val),
None => println!("索引越界"),
}
// 遍历
for val in &v {
println!("{}", val);
}
for val in &mut v {
*val += 10;
}
// 删除
let popped = v.pop(); // Option<T>
v.remove(0); // 按索引删除(O(n))
v.swap_remove(0); // 交换后删除(O(1))
v.retain(|&x| x > 1); // 条件保留
v.clear(); // 清空
v.truncate(3); // 截断到指定长度
v.drain(1..3); // 删除范围并返回迭代器
// 常用操作
let mut v = vec![3, 1, 4, 1, 5];
v.sort(); // [1,1,3,4,5]
v.sort_unstable(); // 快速排序,不稳定
v.sort_by(|a, b| b.cmp(a)); // 自定义排序
v.dedup(); // [1,3,4,5] 去除相邻重复
v.reverse();
v.contains(&3); // true
v.binary_search(&3); // 二分查找(需已排序)
let sum: i32 = v.iter().sum();
let first = v.first(); // Option<&T>
let last = v.last(); // Option<&T>
v.is_empty();
v.len();
v.capacity();
v.as_slice(); // 转为切片
v.into_boxed_slice(); // 转为 Box<[T]>
}
String - 字符串
fn main() {
// 创建
let s1 = String::new();
let s2 = String::from("hello");
let s3 = "world".to_string();
let s4: String = "中文".into();
let s5 = String::with_capacity(100);
// 修改
let mut s = String::from("hello");
s.push_str(" world");
s.push('!');
s.insert(0, 'H'); // 插入字符
s.insert_str(5, " there"); // 插入字符串
s.remove(0); // 删除字符
s.pop(); // Option<char>
s.clear();
s.truncate(5);
s.replace_range(0..5, "Hi");
// 拼接
let s1 = String::from("hello");
let s2 = String::from(" world");
let s3 = s1 + &s2; // s1 被移动,+ 实际是 add(self, &str)
let s4 = format!("{}-{}", s2, "rust"); // 不移动,推荐
// 不能索引(UTF-8 可变长度)
// let c = s[0]; // 编译错误
// 遍历
for c in "你好世界".chars() {
println!("{}", c);
}
for b in "abc".bytes() {
println!("{}", b);
}
// char_indices 返回 (字节索引, 字符)
for (i, c) in "你好".char_indices() {
println!("{}: {}", i, c); // 0:你, 3:好
}
// 字符串方法
let s = String::from(" Hello, World! ");
s.len(); // 字节长度
s.chars().count(); // 字符数
s.is_empty();
s.contains("World"); // true
s.starts_with("Hello"); // false (有前导空格)
s.ends_with("!");
s.find("World"); // Option<usize> 字节索引
s.trim(); // "Hello, World!"
s.trim_start();
s.trim_end();
s.to_lowercase();
s.to_uppercase();
s.replace("World", "Rust");
s.split(","); // 迭代器
s.split_whitespace();
s.lines();
s.matches("l"); // 匹配迭代器
s.parse::<i32>(); // 转为数字
}
HashMap<K, V>
use std::collections::HashMap;
fn main() {
// 创建
let mut scores: HashMap<String, i32> = HashMap::new();
scores.insert(String::from("Alice"), 95);
scores.insert(String::from("Bob"), 87);
// 从 Vec 构建
let teams = vec![String::from("Blue"), String::from("Red")];
let scores = vec![10, 50];
let map: HashMap<_, _> = teams.into_iter().zip(scores.into_iter()).collect();
// 访问
let alice_score = scores.get("Alice"); // Option<&i32>
if let Some(score) = scores.get("Alice") {
println!("Alice: {}", score);
}
// entry API(最常用)
scores.entry(String::from("Alice")).or_insert(50); // 不存在则插入
scores.entry(String::from("Charlie")).or_insert(80);
// 基于旧值更新
let text = "hello world hello";
let mut map = HashMap::new();
for word in text.split_whitespace() {
let count = map.entry(word).or_insert(0);
*count += 1;
}
println!("{:?}", map);
// and_modify (Rust 1.50+)
scores.entry(String::from("Alice"))
.and_modify(|v| *v += 5)
.or_insert(50);
// 遍历
for (key, val) in &scores {
println!("{}: {}", key, val);
}
// 删除
scores.remove("Bob");
scores.retain(|k, v| *v > 80);
scores.clear();
// 其他方法
scores.len();
scores.is_empty();
scores.contains_key("Alice");
scores.keys(); // 迭代器
scores.values(); // 迭代器
scores.values_mut();
}
HashSet<T>
use std::collections::HashSet;
fn main() {
let mut set: HashSet<i32> = HashSet::new();
set.insert(1);
set.insert(2);
set.insert(3);
set.insert(2); // 重复,不会添加
set.contains(&1); // true
set.len(); // 3
// 集合操作
let a: HashSet<_> = [1, 2, 3].iter().collect();
let b: HashSet<_> = [2, 3, 4].iter().collect();
// 交集
let intersection: HashSet<_> = a.intersection(&b).collect(); // {2, 3}
// 并集
let union: HashSet<_> = a.union(&b).collect(); // {1, 2, 3, 4}
// 差集
let diff: HashSet<_> = a.difference(&b).collect(); // {1}
// 对称差
let sym_diff: HashSet<_> = a.symmetric_difference(&b).collect(); // {1, 4}
// 子集/超集判断
let small: HashSet<_> = [1, 2].iter().collect();
small.is_subset(&a); // true
a.is_superset(&small); // true
}
VecDeque<T> - 双端队列
use std::collections::VecDeque;
fn main() {
let mut deque = VecDeque::new();
deque.push_front(1); // 前端添加
deque.push_back(2); // 后端添加
deque.push_front(0); // [0, 1, 2]
deque.pop_front(); // Some(0)
deque.pop_back(); // Some(2)
// 作为队列使用(FIFO)
let mut queue = VecDeque::new();
queue.push_back(1);
queue.push_back(2);
let first = queue.pop_front(); // Some(1)
// 作为栈使用(LIFO)
let mut stack = VecDeque::new();
stack.push_back(1);
stack.push_back(2);
let last = stack.pop_back(); // Some(2)
}
BTreeMap 和 BTreeSet
use std::collections::{BTreeMap, BTreeSet};
fn main() {
// BTreeMap - 按键排序的 Map(红黑树实现)
let mut map = BTreeMap::new();
map.insert("c", 3);
map.insert("a", 1);
map.insert("b", 2);
// 遍历时按键排序:a, b, c
// 范围查询(HashMap 不支持)
for (k, v) in map.range("a".."c") {
println!("{}: {}", k, v);
}
// BTreeSet - 排序的集合
let mut set = BTreeSet::new();
set.insert(3);
set.insert(1);
set.insert(2);
// 遍历时按值排序:1, 2, 3
}
// HashMap vs BTreeMap 选择:
// HashMap: O(1) 平均查找,无序,更快(大多数场景)
// BTreeMap: O(log n) 查找,有序,支持范围查询
BinaryHeap<T> - 优先队列
use std::collections::BinaryHeap;
fn main() {
let mut heap = BinaryHeap::new();
heap.push(3);
heap.push(1);
heap.push(5);
heap.push(2);
// 默认是大顶堆
heap.peek(); // Some(&5)
heap.pop(); // Some(5)
heap.pop(); // Some(3)
// 转为小顶堆(使用 Reverse)
use std::cmp::Reverse;
let mut min_heap = BinaryHeap::new();
min_heap.push(Reverse(3));
min_heap.push(Reverse(1));
min_heap.push(Reverse(5));
min_heap.pop(); // Some(Reverse(1))
}
9. 字符串深入
▼
字符串类型区别
| 类型 | 说明 | 所有权 | 可变 |
|---|---|---|---|
String | UTF-8 字符串,堆分配 | 拥有 | 可变 |
&str | 字符串切片,UTF-8 | 借用 | 不可变 |
&mut str | 可变字符串切片(很少用) | 借用 | 可变 |
OsString | 操作系统原生字符串 | 拥有 | 可变 |
&OsStr | 操作系统字符串切片 | 借用 | 不可变 |
PathBuf | 路径,堆分配 | 拥有 | 可变 |
&Path | 路径切片 | 借用 | 不可变 |
CString | C 兼容的字符串(\0 结尾) | 拥有 | 可变 |
&CStr | C 字符串切片 | 借用 | 不可变 |
UTF-8 编码细节
fn main() {
let hello = "नमस्ते"; // 印地语 "你好"
// 字节长度(每个字符 3 字节)
println!("字节: {}", hello.len()); // 18
println!("字符: {}", hello.chars().count()); // 6
// 不能按字节索引(可能切在多字节字符中间)
// &hello[0..3]; // 可能 panic(如果不是字符边界)
// 安全按字节切片(需检查边界)
let safe_slice = if hello.is_char_boundary(3) {
&hello[0..3] // OK,如果是字符边界
} else {
""
};
// Unicode 组合字符
let hello = "Hello";
let mut hello2 = String::from(hello);
hello2.push('\u{0301}'); // 组合锐音符
println!("{}", hello2); // Héllo
println!("字符数: {}", hello2.chars().count()); // 6
// Grapheme clusters(字形簇,人类视角的"字符")
// 需要 unicode-segmentation crate
use unicode_segmentation::UnicodeSegmentation;
let s = "é"; // e + 组合符
println!("graphemes: {}", s.graphemes(true).count()); // 1
println!("chars: {}", s.chars().count()); // 2
}
字符串性能优化
fn main() {
// 1. 预分配容量
let mut s = String::with_capacity(1000);
for i in 0..1000 {
s.push_str("abc"); // 不会重新分配
}
// 2. 使用 Cow(Clone on Write)
use std::borrow::Cow;
fn remove_spaces(s: &str) -> Cow<str> {
if s.contains(' ') {
Cow::Owned(s.replace(" ", ""))
} else {
Cow::Borrowed(s) // 无需拷贝
}
}
let r1 = remove_spaces("hello"); // 借用
let r2 = remove_spaces("hello world"); // 拥有
// 3. 使用 format! 宏
let s = format!("{} + {} = {}", 1, 2, 3);
// 4. 使用 write! 宏
use std::fmt::Write;
let mut s = String::new();
write!(s, "{} {}", "hello", "world").unwrap();
// 5. String::from_utf8 转换字节
let bytes = vec![72, 101, 108, 108, 111];
let s = String::from_utf8(bytes).unwrap(); // "Hello"
// 6. String::from_utf8_lossy(容错转换)
let invalid = vec![0xff, 0xfe];
let s = String::from_utf8_lossy(&invalid); // 无效字节替换为 U+FFFD
}
字符串格式化
fn main() {
// 基础格式化
println!("{}", "hello"); // Display
println!("{:?}", (1, 2)); // Debug
println!("{:#?}", (1, 2)); // Pretty Debug
println!("{:x}", 255); // ff (小写十六进制)
println!("{:X}", 255); // FF (大写十六进制)
println!("{:b}", 255); // 11111111 (二进制)
println!("{:o}", 255); // 377 (八进制)
println!("{:e}", 1000.0); // 1e3 (科学计数法)
// 位置参数
println!("{0} {1} {0}", "hello", "world");
// 命名参数
println!("{name} is {age}", name="Alice", age=30);
// 宽度与对齐
println!("{:10}", "x"); // "x " (左对齐)
println!("{:>10}", "x"); // " x" (右对齐)
println!("{:^10}", "x"); // " x " (居中)
println!("{:*^10}", "x"); // "****x*****" (填充 *)
// 精度
println!("{:.2}", 3.14159); // 3.14
println!("{:.5}", "hello world"); // hello (截断)
// 捕获变量 (Rust 1.58+)
let name = "Rust";
let version = "1.75";
println!("{name} {version}"); // 直接捕获
// 数字格式
println!("{:#06x}", 255); // 0x00ff
println!("{:08}", 42); // 00000042
println!("{:08.3}", 3.1415); // 0003.142
}
10. 错误处理
▼
panic! - 不可恢复错误
fn main() {
// 主动 panic
// panic!("crash!");
// 隐式 panic(数组越界、unwrap 失败等)
let v = vec![1, 2, 3];
// v[99]; // 越界 panic
// 设置 panic 行为(Cargo.toml)
# [profile.release]
# panic = 'abort' # 直接终止,无回溯
# [profile.dev]
# panic = 'unwind' # 默认,允许捕获
// 捕获 panic(谨慎使用)
let result = std::panic::catch_unwind(|| {
panic!("oh no!");
});
assert!(result.is_err());
}
Result<T, E> - 可恢复错误
use std::fs::File;
use std::io::{self, Read};
fn read_file(path: &str) -> Result<String, io::Error> {
let file_result = File::open(path);
let mut file = match file_result {
Ok(f) => f,
Err(e) => return Err(e),
};
let mut content = String::new();
match file.read_to_string(&mut content) {
Ok(_) => Ok(content),
Err(e) => Err(e),
}
}
// 使用 ? 运算符简化(只能用在返回 Result 的函数中)
fn read_file_v2(path: &str) -> Result<String, io::Error> {
let mut file = File::open(path)?;
let mut content = String::new();
file.read_to_string(&mut content)?;
Ok(content)
}
// 链式调用
fn read_file_v3(path: &str) -> Result<String, io::Error> {
File::open(path)
.and_then(|mut file| {
let mut s = String::new();
file.read_to_string(&mut s).map(|_| s)
})
}
// 链式写法 2
fn read_file_v4(path: &str) -> Result<String, io::Error> {
let mut s = String::new();
File::open(path)?.read_to_string(&mut s)?;
Ok(s)
}
// 使用 std::fs::read_to_string 最简洁
fn read_file_v5(path: &str) -> Result<String, io::Error> {
std::fs::read_to_string(path)
}
Result 常用方法
fn main() {
let r: Result<i32, &str> = Ok(5);
let e: Result<i32, &str> = Err("error");
// 解包
r.unwrap(); // 5
r.unwrap_or(0); // 5
e.unwrap_or(0); // 0
e.unwrap_or_default(); // 0
e.unwrap_or_else(|_| 0); // 0
// e.unwrap(); // panic
r.expect("Failed"); // 5,失败显示信息
// 判断
r.is_ok(); // true
r.is_err(); // false
// 转换
r.ok(); // Some(5)
e.ok(); // None
r.err(); // None
e.err(); // Some("error")
// 链式
r.map(|v| v * 2); // Ok(10)
r.map_err(|e| e.to_string());
r.and_then(|v| Ok(v * 2)); // Ok(10)
r.or_else(|_| Ok(0)); // Ok(5)
e.or_else(|_| Ok(0)); // Ok(0)
// 扁平化
let nested: Result<Result<i32, &str>, &str> = Ok(Ok(5));
nested.flatten(); // Ok(5)
}
自定义错误类型
use std::fmt;
use std::error::Error;
#[derive(Debug)]
enum AppError {
NotFound(String),
Unauthorized,
ParseError(std::num::ParseIntError),
Io(std::io::Error),
}
impl fmt::Display for AppError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AppError::NotFound(msg) => write!(f, "未找到: {}", msg),
AppError::Unauthorized => write!(f, "未授权"),
AppError::ParseError(e) => write!(f, "解析错误: {}", e),
AppError::Io(e) => write!(f, "IO 错误: {}", e),
}
}
}
impl Error for AppError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
AppError::ParseError(e) => Some(e),
AppError::Io(e) => Some(e),
_ => None,
}
}
}
// 从其他错误类型转换
impl From<std::num::ParseIntError> for AppError {
fn from(err: std::num::ParseIntError) -> Self {
AppError::ParseError(err)
}
}
impl From<std::io::Error> for AppError {
fn from(err: std::io::Error) -> Self {
AppError::Io(err)
}
}
// 使用 thiserror crate 简化
use thiserror::Error;
#[derive(Error, Debug)]
enum AppError {
#[error("未找到: {0}")]
NotFound(String),
#[error("未授权")]
Unauthorized,
#[error("解析错误")]
ParseError(#[from] std::num::ParseIntError),
#[error("IO 错误")]
Io(#[from] std::io::Error),
#[error("自定义错误: {code} - {msg}")]
Custom { code: i32, msg: String },
}
推荐在库代码中使用
Result
+
thiserror
返回错误,在应用顶层(main)使用
anyhow
处理错误。
anyhow::Result<T>
是
Result<T, anyhow::Error>
的别名,支持任意错误类型和
.context()
方法添加上下文。
使用 anyhow 简化错误处理
use anyhow::{Result, Context, anyhow};
fn read_config() -> Result<Config> {
let content = std::fs::read_to_string("config.toml")
.context("无法读取配置文件")?;
let config: Config = toml::from_str(&content)
.context("配置文件格式错误")?;
Ok(config)
}
fn main() -> Result<()> {
let config = read_config()?;
println!("{:?}", config);
// 创建自定义错误
if config.is_invalid() {
return Err(anyhow!("Invalid config"));
}
Ok(())
}
11. 泛型
▼
泛型函数
// 单类型参数
fn largest<T: PartialOrd>(list: &[T]) -> &T {
let mut largest = &list[0];
for item in &list[1..] {
if item > largest {
largest = item;
}
}
largest
}
// 多类型参数
fn print_pair<T, U>(t: T, u: U)
where
T: std::fmt::Display,
U: std::fmt::Display,
{
println!("({}, {})", t, u);
}
// 带返回值的泛型
fn wrap<T>(x: T) -> Option<T> {
Some(x)
}
// turbofish 语法(显式指定类型参数)
let v = Vec::<i32>::new();
let s = "42".parse::<i32>().unwrap();
let v = vec![1, 2, 3].into_iter().collect::<Vec<_>>();
泛型结构体
struct Point<T> {
x: T,
y: T,
}
struct Pair<T, U> {
first: T,
second: U,
}
// 带默认类型参数
struct Array<T, const N: usize> {
data: [T; N],
}
// 为泛型结构体实现方法
impl<T> Point<T> {
fn x(&self) -> &T {
&self.x
}
}
// 为特定类型实现方法
impl Point<f64> {
fn distance_from_origin(&self) -> f64 {
(self.x.powi(2) + self.y.powi(2)).sqrt()
}
}
// 常量泛型参数
fn create_zero_array<T: Default + Copy, const N: usize>() -> [T; N] {
[T::default(); N]
}
let zeros: [i32; 5] = create_zero_array();
fn main() {
let integer_point = Point { x: 5, y: 10 };
let float_point = Point { x: 1.5, y: 4.2 };
println!("x = {}", integer_point.x());
println!("距离: {}", float_point.distance_from_origin());
}
泛型枚举
// 标准库中的 Option 和 Result
enum Option<T> {
Some(T),
None,
}
enum Result<T, E> {
Ok(T),
Err(E),
}
// 自定义泛型枚举
enum List<T> {
Cons(T, Box<List<T>>),
Nil,
}
// Either 类型(两个结果之一)
enum Either<L, R> {
Left(L),
Right(R),
}
性能:Monomorphization
Rust 通过 单态化(monomorphization) 实现零成本抽象:编译器在编译时为每个实际使用的具体类型生成独立的代码。
// 编译器会将以下代码:
let integer = Some(5); // Option<i32>
let float = Some(5.0); // Option<f64>
// 转换为类似:
enum Option_i32 { Some(i32), None }
enum Option_f64 { Some(f64), None }
let integer = Option_i32::Some(5);
let float = Option_f64::Some(5.0);
// 因此运行时没有泛型的性能开销
单态化的代价是
编译产物体积增大
和
编译时间变长
。如果需要减少代码膨胀,可以使用
dyn Trait
(trait object,动态分发)。
12. Trait 特征
▼
定义和实现 Trait
trait Summary {
fn summarize(&self) -> String;
// 默认实现
fn preview(&self) -> String {
format!("(Read more... {})", self.summarize())
}
}
struct Article {
title: String,
author: String,
content: String,
}
impl Summary for Article {
fn summarize(&self) -> String {
format!("{}, by {} - {}", self.title, self.author, &self.content[..20])
}
}
struct Tweet {
username: String,
content: String,
}
impl Summary for Tweet {
fn summarize(&self) -> String {
format!("@{}: {}", self.username, self.content)
}
// 重写默认方法
fn preview(&self) -> String {
format!("[Tweet] {}", self.summarize())
}
}
孤儿规则(Orphan Rule)
只能在本地定义的类型或本地定义的 trait 之间实现关系。即不能为第三方库的类型实现第三方库的 trait,防止冲突。
// OK:本地类型 + 本地 trait
impl MyTrait for MyType { }
// OK:本地类型 + 标准库 trait
impl std::fmt::Display for MyType { }
// OK:标准库 trait + 本地类型(通过泛型)
impl<T> std::fmt::Display for MyWrapper<T> { }
// 错误:第三方类型 + 第三方 trait
// impl std::fmt::Display for serde_json::Value { } // 错误!
// 解决方案:使用 Newtype 模式
struct MyValue(serde_json::Value);
impl std::fmt::Display for MyValue { }
Trait 作为参数
// impl Trait 语法(静态分发,编译时确定类型)
fn notify(item: &impl Summary) {
println!("突发: {}", item.summarize());
}
// Trait Bound 语法
fn notify<T: Summary>(item: &T) {
println!("突发: {}", item.summarize());
}
// 多 Trait Bound
fn notify(item: &impl Summary + std::fmt::Display) { }
// where 从句(更清晰,特别是复杂约束时)
fn some_function<T, U>(t: &T, u: &U) -> i32
where
T: Display + Clone,
U: Clone + Debug,
{
0
}
// 返回 impl Trait(只能返回一种类型)
fn create_summary() -> impl Summary {
Tweet {
username: String::from("rust"),
content: String::from("Hello!"),
}
}
// 返回多种类型时使用 trait object(dyn)
fn create_summary(is_tweet: bool) -> Box<dyn Summary> {
if is_tweet {
Box::new(Tweet { /*...*/ })
} else {
Box::new(Article { /*...*/ })
}
}
常用标准库 Trait
// 自动派生
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
struct User {
name: String,
age: u32,
}
// Display trait
use std::fmt;
impl fmt::Display for User {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "User({}, {})", self.name, self.age)
}
}
// From / Into(类型转换)
impl From<&str> for User {
fn from(s: &str) -> Self {
User {
name: s.to_string(),
age: 0,
}
}
}
let user: User = "Alice".into();
// Iterator trait
struct Counter { count: u32 }
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
self.count += 1;
if self.count <= 5 {
Some(self.count)
} else {
None
}
}
}
// Add / Sub / Mul / Div 等运算 trait
use std::ops::Add;
impl Add for Point {
type Output = Self;
fn add(self, other: Self) -> Self {
Self {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
let p3 = p1 + p2; // 调用 add
// Index trait
use std::ops::Index;
impl Index<usize> for MyVec {
type Output = i32;
fn index(&self, index: usize) -> &Self::Output {
&self.data[index]
}
}
关联类型(Associated Types)
// 与泛型不同,关联类型只能有一个具体实现
pub trait Iterator {
type Item; // 关联类型
fn next(&mut self) -> Option<Self::Item>;
}
impl Iterator for Counter {
type Item = u32; // 指定具体类型
fn next(&mut self) -> Option<Self::Item> {
/* ... */
}
}
// 对比泛型 trait(可以多次实现)
pub trait Iterator<T> {
fn next(&mut self) -> Option<T>;
}
// 可以分别为不同类型实现
impl Iterator<u32> for Counter { }
impl Iterator<i32> for Counter { } // 也允许
完全限定语法(Fully Qualified Syntax)
trait Pilot {
fn fly(&self);
}
trait Wizard {
fn fly(&self);
}
struct Human;
impl Pilot for Human {
fn fly(&self) {
println!("This is your captain speaking.");
}
}
impl Wizard for Human {
fn fly(&self) {
println!("Up!");
}
}
impl Human {
fn fly(&self) {
println!(*waving arms furiously*);
}
}
fn main() {
let h = Human;
h.fly(); // 默认调用 Human 的 fly
Pilot::fly(&h); // 调用 Pilot 的 fly
Wizard::fly(&h); // 调用 Wizard 的 fly
// 没有 self 参数的情况
trait Animal {
fn baby_name() -> String;
}
struct Dog;
impl Dog {
fn baby_name() -> String { String::from("Spot") }
}
impl Animal for Dog {
fn baby_name() -> String { String::from("puppy") }
}
println!("{}", Dog::baby_name()); // Spot
println!("{}", <Dog as Animal>::baby_name()); // puppy
}
Supertrait
use std::fmt;
// 实现 OutlinePrint 的类型必须也实现 Display
trait OutlinePrint: fmt::Display {
fn outline(&self) {
println!("**********");
println!("* {} *", self);
println!("**********");
}
}
struct Point { x: i32, y: i32 }
// 必须先实现 Display 才能实现 OutlinePrint
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
impl OutlinePrint for Point {}
Trait Object (动态分发)
trait Drawable {
fn draw(&self);
fn area(&self) -> f64;
}
struct Circle { radius: f64 }
impl Drawable for Circle {
fn draw(&self) { println!("○"); }
fn area(&self) -> f64 { std::f64::consts::PI * self.radius.powi(2) }
}
struct Square { side: f64 }
impl Drawable for Square {
fn draw(&self) { println!("□"); }
fn area(&self) -> f64 { self.side.powi(2) }
}
// 使用 trait object
fn draw_all(shapes: &[&dyn Drawable]) {
for shape in shapes {
shape.draw();
println!("面积: {}", shape.area());
}
}
fn main() {
let shapes: Vec<Box<dyn Drawable>> = vec![
Box::new(Circle { radius: 5.0 }),
Box::new(Square { side: 4.0 }),
];
for shape in &shapes {
shape.draw();
}
}
// 对象安全(Object Safety)要求:
// 1. 方法不能有泛型参数
// 2. 方法不能返回 Self(除非 Sized)
// 3. 不能有非静态生命周期的返回引用
13. 生命周期
▼
生命周期基础
生命周期确保引用在使用时始终有效:
// 这段代码无法编译
// {
// let r;
// {
// let x = 5;
// r = &x; // x 的生命周期短于 r
// }
// println!("{}", r); // 悬垂引用!
// }
// 需要显式标注生命周期的情况
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
fn main() {
let s1 = String::from("long string");
let result;
{
let s2 = String::from("xyz");
result = longest(s1.as_str(), s2.as_str());
println!("{}", result); // OK,s2 仍然有效
}
// println!("{}", result); // 错误!s2 已失效
}
生命周期省略规则
编译器会自动推断一些常见情况:
// 编译器自动推断(不需要标注)
fn first_word(s: &str) -> &str { } // OK - 规则 1+2
fn len(s: &str) -> usize { } // OK - 无输出引用
impl MyStruct {
fn get_name(&self) -> &str { } // OK - 规则 3
}
// 需要显式标注
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { }
// 方法中的生命周期
struct Important<'a> {
part: &'a str,
}
impl<'a> Important<'a> {
fn level(&self) -> i32 { 3 } // 不需要标注
fn announce(&self, announcement: &str) -> &str { // 有歧义
// 需要标注:&self 还是 announcement?
self.part
}
}
结构体中的生命周期
// 包含引用的结构体必须标注生命周期
struct Excerpt<'a> {
part: &'a str,
}
impl<'a> Excerpt<'a> {
// 返回引用的方法
fn level(&self) -> i32 { 3 }
// 返回结构体字段引用的方法
fn part(&self) -> &str {
self.part
}
// 返回传入参数的引用(不同的生命周期)
fn announce_and_return<'b>(&self, announcement: &'b str) -> &'b str {
println!("Attention: {}", announcement);
announcement
}
}
fn main() {
let novel = String::from("Call me Ishmael. Some years ago...");
let first_sentence = novel.split('.').next().expect("Could not find '.'");
let i = Excerpt {
part: first_sentence, // first_sentence 的生命周期足够长
};
println!("{}", i.part());
}
静态生命周期
// 'static 生命周期:贯穿整个程序运行期
let s: &'static str = "I have a static lifetime";
// 字符串字面量默认是 'static 的(存储在二进制文件中)
fn get_static() -> &'static str {
"this lives forever"
}
// 注意:'static 不一定意味着"永远存活"
// 而是意味着"可以永远存活"(数据存储在只读内存中)
// 但引用本身可以提前丢弃
生命周期子类型
// 'a 活得比 'b 久:'a: 'b
fn example<'a: 'b, 'b>(x: &'a str, y: &'b str) -> &'b str {
// 可以返回 y,也可以返回 x(因为 'a 比 'b 长)
if x.len() > y.len() { x } else { y }
}
14. 闭包与迭代器
▼
闭包(Closures)
闭包是可以捕获环境的匿名函数:
fn main() {
// 基本语法
let add_one = |x: i32| -> i32 { x + 1 };
let multiply = |x, y| x * y;
let add = |x, y| { x + y };
// 类型推断
let expensive = |x: i32| -> i32 {
println!("calculating...");
x * 2
};
// 捕获环境变量(三种方式)
let name = String::from("world");
let greet = || println!("Hello, {}!", name); // 不可变借用 &T
greet();
println!("{}", name); // name 仍然可用
// 可变借用
let mut count = 0;
let mut inc = || {
count += 1;
println!("count: {}", count);
};
inc();
inc();
println!("final: {}", count);
// 获取所有权(move)
let s = String::from("hello");
let consume = move || {
println!("{}", s);
};
// s 不再可用,所有权已转移给闭包
consume();
// move 在多线程中特别重要
use std::thread;
let data = vec![1, 2, 3];
thread::spawn(move || {
println!("Captured: {:?}", data);
}).join().unwrap();
}
Fn Trait 族
// FnOnce: 只能调用一次,获取所有权(自动实现于所有闭包)
// FnMut: 可以多次调用,可变借用
// Fn: 可以多次调用,不可变借用
// 关系:Fn <: FnMut <: FnOnce
// 实现了 Fn 的闭包也自动实现了 FnMut 和 FnOnce
fn apply_once<F: FnOnce(i32) -> i32>(f: F, x: i32) -> i32 {
f(x)
}
fn apply_mut<F: FnMut()>(mut f: F) {
f();
f();
}
fn apply_ref<F: Fn()>(f: F) {
f();
f();
f();
}
// 返回闭包
fn make_adder(x: i32) -> impl Fn(i32) -> i32 {
move |y| x + y
}
// 需要 FnMut 时用 Box
fn make_counter() -> Box<dyn FnMut() -> i32> {
let mut count = 0;
Box::new(move || {
count += 1;
count
})
}
fn main() {
let add5 = make_adder(5);
println!("{}", add5(3)); // 8
let mut counter = make_counter();
println!("{}", counter()); // 1
println!("{}", counter()); // 2
}
迭代器
fn main() {
let v = vec![1, 2, 3, 4, 5];
// iter() - 不可变引用(最常用)
for val in v.iter() {
println!("{}", val);
}
// into_iter() - 获取所有权
for val in v.into_iter() {
println!("{}", val);
}
// iter_mut() - 可变引用
let mut v = vec![1, 2, 3];
for val in v.iter_mut() {
*val *= 2;
}
// 常用迭代器适配器
let v = vec![1, 2, 3, 4, 5];
let doubled: Vec<_> = v.iter().map(|x| x * 2).collect();
let evens: Vec<_> = v.iter().filter(|x| x % 2 == 0).collect();
let sum: i32 = v.iter().sum();
let count = v.iter().count();
let max = v.iter().max();
let min = v.iter().min();
// 链式调用
let result: Vec<_> = (1..10)
.filter(|x| x % 2 != 0)
.map(|x| x * x)
.take(3)
.collect(); // [1, 9, 25]
// fold / reduce
let sum = v.iter().fold(0, |acc, &x| acc + x);
let product = v.iter().product::<i32>();
let reduced = v.iter().copied().reduce(|acc, x| acc + x);
// enumerate
for (i, val) in v.iter().enumerate() {
println!("[{}]: {}", i, val);
}
// zip
let names = vec!["Alice", "Bob"];
let ages = vec![30, 25];
let zipped: Vec<_> = names.iter().zip(ages.iter()).collect();
// any / all
let has_even = v.iter().any(|&x| x % 2 == 0);
let all_positive = v.iter().all(|&x| x > 0);
// find / position
let first_even = v.iter().find(|&x| x % 2 == 0);
let pos = v.iter().position(|&x| x == 3);
// flatten / flat_map
let nested = vec![vec![1, 2], vec![3, 4]];
let flat: Vec<_> = nested.iter().flatten().collect(); // [1,2,3,4]
// partition
let (evens, odds): (Vec<_>, Vec<_>) = v.iter().partition(|&x| x % 2 == 0);
// inspect (调试用)
v.iter()
.inspect(|x| println!("before: {}", x))
.map(|x| x * 2)
.inspect(|x| println!("after: {}", x))
.for_each(|x| println!("result: {}", x));
}
15. 迭代器进阶
▼
Iterator trait 详解
pub trait Iterator {
type Item;
// 必须实现
fn next(&mut self) -> Option<Self::Item>;
// 提供默认实现的常用方法:
fn size_hint(&self) -> (usize, Option<usize>);
fn count(self) -> usize;
fn last(self) -> Option<Self::Item>;
fn nth(&mut self, n: usize) -> Option<Self::Item>;
fn step_by(self, step: usize) -> StepBy<Self>;
fn chain<U>(self, other: U) -> Chain<Self, U::IntoIter>;
fn zip<U>(self, other: U) -> Zip<Self, U::IntoIter>;
fn map<B, F>(self, f: F) -> Map<Self, F>;
fn filter<P>(self, predicate: P) -> Filter<Self, P>;
fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F>;
fn enumerate(self) -> Enumerate<Self>;
fn peekable(self) -> Peekable<Self>;
fn skip(self, n: usize) -> Skip<Self>;
fn take(self, n: usize) -> Take<Self>;
fn take_while<P>(self, predicate: P) -> TakeWhile<Self, P>;
fn skip_while<P>(self, predicate: P) -> SkipWhile<Self, P>;
fn flat_map<F, U>(self, f: F) -> FlatMap<Self, U, F>;
fn flatten(self) -> Flatten<Self>;
fn fuse(self) -> Fuse<Self>;
fn inspect<F>(self, f: F) -> Inspect<Self, F>;
fn by_ref(&mut self) -> &mut Self;
fn fold<B, F>(self, init: B, f: F) -> B;
fn all<F>(&mut self, f: F) -> bool;
fn any<F>(&mut self, f: F) -> bool;
fn find<P>(&mut self, predicate: P) -> Option<Self::Item>;
fn find_map<B, F>(&mut self, f: F) -> Option<B>;
fn position<P>(&mut self, predicate: P) -> Option<usize>;
fn collect<B: FromIterator<Self::Item>>(self) -> B;
fn partition<B, F>(self, f: F) -> (B, B);
fn for_each<F>(self, f: F);
fn sum<S>(self) -> S;
fn product<P>(self) -> P;
fn min(self) -> Option<Self::Item>;
fn max(self) -> Option<Self::Item>;
fn min_by_key<B, F>(self, f: F) -> Option<Self::Item>;
fn max_by_key<B, F>(self, f: F) -> Option<Self::Item>;
fn rev(self) -> Rev<Self>;
fn unzip<A, B, FromA, FromB>(self) -> (FromA, FromB);
fn copied<'a, T>(self) -> Copied<Self>;
fn cloned<'a, T>(self) -> Cloned<Self>;
fn cycle(self) -> Cycle<Self>;
}
IntoIterator trait
// for 循环自动调用 into_iter()
for item in collection {
// ...
}
// 等价于:
let mut iter = collection.into_iter();
while let Some(item) = iter.next() {
// ...
}
// 三种迭代方式
let v = vec![1, 2, 3];
// 1. &Vec<T> -> IntoIterator (不可变引用)
for x in &v { } // x: &i32
// 2. &mut Vec<T> -> IntoIterator (可变引用)
for x in &mut v { } // x: &mut i32
// 3. Vec<T> -> IntoIterator (所有权)
for x in v { } // x: i32
自定义迭代器
// 斐波那契数列迭代器
struct Fibonacci {
a: u64,
b: u64,
}
impl Fibonacci {
fn new() -> Self {
Fibonacci { a: 0, b: 1 }
}
}
impl Iterator for Fibonacci {
type Item = u64;
fn next(&mut self) -> Option<Self::Item> {
let result = self.a;
let next = self.a + self.b;
self.a = self.b;
self.b = next;
Some(result)
}
}
fn main() {
let fib: Vec<_> = Fibonacci::new().take(10).collect();
println!("{:?}", fib); // [0,1,1,2,3,5,8,13,21,34]
// 过滤偶数
let even_fibs: Vec<_> = Fibonacci::new()
.filter(|&x| x % 2 == 0)
.take(5)
.collect();
println!("{:?}", even_fibs); // [0,2,8,34,144]
}
// 范围类型迭代器
struct Range {
current: i32,
end: i32,
}
impl Iterator for Range {
type Item = i32;
fn next(&mut self) -> Option<Self::Item> {
if self.current < self.end {
let result = self.current;
self.current += 1;
Some(result)
} else {
None
}
}
}
// 实现 ExactSizeIterator 提供精确长度信息
impl ExactSizeIterator for Range {
fn len(&self) -> usize {
(self.end - self.current) as usize
}
}
// 实现 DoubleEndedIterator 支持反向迭代
impl DoubleEndedIterator for Range {
fn next_back(&mut self) -> Option<Self::Item> {
if self.current < self.end {
self.end -= 1;
Some(self.end)
} else {
None
}
}
}
迭代器性能
Rust 迭代器是惰性求值(lazy)的,只有调用消耗器(如 collect、for)时才会执行。编译器能极大优化迭代器链:
// 编译器会优化成类似这样的代码:
let result: Vec<i32> = (1..100)
.filter(|x| x % 2 == 0)
.map(|x| x * 2)
.collect();
// 优化后:
let mut result = Vec::new();
for x in 1..100 {
if x % 2 == 0 {
result.push(x * 2);
}
}
// 甚至进一步优化为无分配、向量化等
最佳实践:
优先使用迭代器而非手写循环。编译器通过内联、循环展开、向量化等技术,通常能让迭代器链达到与手写循环相同甚至更好的性能。
FromIterator trait
// 让类型可以通过 collect() 收集
use std::iter::FromIterator;
struct MyCollection {
data: Vec<i32>,
}
impl FromIterator<i32> for MyCollection {
fn from_iter<I: IntoIterator<Item = i32>>(iter: I) -> Self {
MyCollection {
data: iter.into_iter().collect(),
}
}
}
let c: MyCollection = (0..10).collect();
// 字符串收集
let s: String = "hello".chars().filter(|c| *c != 'l').collect(); // "heo"
// HashMap 收集
use std::collections::HashMap;
let pairs = vec![("a", 1), ("b", 2)];
let map: HashMap<_, _> = pairs.into_iter().collect();
16. 智能指针
▼
Box<T> - 堆上分配
fn main() {
// 将数据放在堆上
let b = Box::new(5);
println!("b = {}", b);
// 递归类型必须用 Box(编译时需要知道大小)
enum List {
Cons(i32, Box<List>),
Nil,
}
use List::{Cons, Nil};
let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
// Box 用于返回 trait object
fn make_shape(kind: &str) -> Box<dyn Drawable> {
match kind {
"circle" => Box::new(Circle { radius: 5.0 }),
_ => Box::new(Square { side: 4.0 }),
}
}
// Box::leak - 永久泄露,获得 'static 引用
let static_str: &'static str = Box::leak(Box::new(String::from("hello")));
}
Rc<T> - 引用计数(单线程)
use std::rc::Rc;
fn main() {
let a = Rc::new(5);
println!("引用计数: {}", Rc::strong_count(&a)); // 1
let b = Rc::clone(&a); // 计数变为 2
let c = Rc::clone(&a); // 计数变为 3
println!("引用计数: {}", Rc::strong_count(&a)); // 3
{
let d = Rc::clone(&a);
println!("引用计数: {}", Rc::strong_count(&a)); // 4
} // d 被 drop,计数变为 3
// Rc 只支持不可变引用
// 需要内部可变性时使用 RefCell
// Weak 弱引用(避免循环引用)
use std::rc::Weak;
let strong = Rc::new(42);
let weak: Weak<i32> = Rc::downgrade(&strong);
println!("strong: {}, weak: {}",
Rc::strong_count(&strong),
Rc::weak_count(&strong));
// 升级弱引用
if let Some(upgraded) = weak.upgrade() {
println!("值: {}", *upgraded);
}
}
// 注意:Rc 不是线程安全的,多线程使用 Arc
RefCell<T> - 内部可变性
use std::cell::RefCell;
fn main() {
let data = RefCell::new(5);
let val = data.borrow(); // 不可变借用 Ref<T>
println!("{}", *val);
{
let mut val_mut = data.borrow_mut(); // 可变借用 RefMut<T>
*val_mut += 10;
}
println!("{}", *data.borrow()); // 15
// 违反借用规则会运行时 panic
// let a = data.borrow();
// let b = data.borrow_mut(); // panic!
// Rc + RefCell = 多所有者 + 可变性
use std::rc::Rc;
let shared = Rc::new(RefCell::new(vec![1, 2, 3]));
let clone1 = Rc::clone(&shared);
shared.borrow_mut().push(4);
println!("{:?}", clone1.borrow());
// try_borrow - 失败返回 Result
let r1 = data.try_borrow();
let r2 = data.try_borrow_mut(); // Err 因为 r1 还持有借用
}
Arc<T> - 原子引用计数(线程安全)
use std::sync::Arc;
use std::thread;
fn main() {
let data = Arc::new(vec![1, 2, 3]);
let handles: Vec<_> = (0..3).map(|i| {
let data = Arc::clone(&data);
thread::spawn(move || {
println!("Thread {}: {:?}", i, data);
})
}).collect();
for h in handles {
h.join().unwrap();
}
}
// Arc<Mutex<T>> = 多线程共享可变数据
use std::sync::Mutex;
let counter = Arc::new(Mutex::new(0));
let c = Arc::clone(&counter);
thread::spawn(move || {
*c.lock().unwrap() += 1;
});
Cow<T> - Clone on Write
use std::borrow::Cow;
// 避免不必要的拷贝
fn remove_spaces(input: &str) -> Cow<str> {
if input.contains(' ') {
Cow::Owned(input.replace(" ", ""))
} else {
Cow::Borrowed(input)
}
}
fn main() {
let a = remove_spaces("hello"); // 借用,无拷贝
let b = remove_spaces("hello world"); // 拥有,拷贝
// 统一使用
println!("a: {}", a);
println!("b: {}", b);
// 转为 owned
let owned: String = a.into_owned();
}
智能指针对比
| 类型 | 作用 | 线程安全 | 可变性 |
|---|---|---|---|
| Box<T> | 堆分配,独占所有权 | 否 | 通过 &mut |
| Rc<T> | 引用计数,多所有者 | 否 | 不可变 |
| Arc<T> | 原子引用计数 | 是 | 不可变 |
| RefCell<T> | 运行时借用检查 | 否 | 内部可变 |
| Mutex<T> | 互斥锁保护 | 是 | 内部可变 |
| RwLock<T> | 读写锁 | 是 | 内部可变 |
| Cow<T> | 写时克隆 | - | - |
17. 并发编程
▼
线程
use std::thread;
use std::time::Duration;
fn main() {
let handle = thread::spawn(|| {
for i in 1..5 {
println!("子线程: {}", i);
thread::sleep(Duration::from_millis(100));
}
});
for i in 1..3 {
println!("主线程: {}", i);
thread::sleep(Duration::from_millis(100));
}
handle.join().unwrap(); // 等待子线程完成
// move 闭包转移所有权
let s = String::from("hello");
let handle = thread::spawn(move || {
println!("{}", s);
});
handle.join().unwrap();
// 线程构建器
let builder = thread::Builder::new()
.name("my-thread".into())
.stack_size(32 * 1024 * 1024); // 32MB
let handler = builder.spawn(|| {
println!("Named thread");
}).unwrap();
// 当前线程信息
let id = thread::current().id();
let name = thread::current().name();
// 线程作用域 (Rust 1.63+)
let mut data = vec![1, 2, 3];
thread::scope(|s| {
s.spawn(|| {
println!("{:?}", data); // 借用 data,安全
});
s.spawn(|| {
data.push(4); // 可变借用
});
}); // 所有线程在此结束
}
消息传递 - Channel
use std::sync::mpsc; // multi-producer, single-consumer
use std::thread;
use std::time::Duration;
fn main() {
let (tx, rx) = mpsc::channel();
// 克隆发送端用于多线程
let tx2 = tx.clone();
thread::spawn(move || {
let vals = vec!["hi", "from", "thread"];
for val in vals {
tx.send(val).unwrap();
thread::sleep(Duration::from_millis(100));
}
});
thread::spawn(move || {
tx2.send("another message").unwrap();
});
// 接收(阻塞)
for received in rx {
println!("收到: {}", received);
}
// 非阻塞接收
match rx.try_recv() {
Ok(msg) => println!("{}", msg),
Err(mpsc::TryRecvError::Empty) => println!("空"),
Err(mpsc::TryRecvError::Disconnected) => println!("已断开"),
}
// 带超时的接收
match rx.recv_timeout(Duration::from_secs(1)) {
Ok(msg) => println!("{}", msg),
Err(e) => println!("Error: {:?}", e),
}
}
共享状态 - Mutex 和 RwLock
use std::sync::{Arc, Mutex, RwLock};
use std::thread;
fn main() {
// Mutex - 互斥锁
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("结果: {}", *counter.lock().unwrap()); // 10
// RwLock - 读写锁(多读单写)
let data = Arc::new(RwLock::new(vec![1, 2, 3]));
// 多个读锁可同时持有
let r1 = Arc::clone(&data);
let r2 = Arc::clone(&data);
thread::spawn(move || {
let read = r1.read().unwrap();
println!("r1: {:?}", *read);
});
thread::spawn(move || {
let read = r2.read().unwrap();
println!("r2: {:?}", *read);
});
// 写锁(独占)
let w = Arc::clone(&data);
thread::spawn(move || {
let mut write = w.write().unwrap();
write.push(4);
});
}
原子类型
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
fn main() {
let counter = Arc::new(AtomicUsize::new(0));
let running = Arc::new(AtomicBool::new(true));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
for _ in 0..1000 {
counter.fetch_add(1, Ordering::SeqCst);
}
});
handles.push(handle);
}
for h in handles {
h.join().unwrap();
}
println!("Final: {}", counter.load(Ordering::SeqCst)); // 10000
}
// 常用原子操作:
// - load: 读取
// - store: 写入
// - swap: 交换
// - compare_exchange: CAS 操作
// - fetch_add, fetch_sub, fetch_or 等
// Ordering 内存顺序:
// - Relaxed: 无同步保证
// - Acquire: 读操作同步
// - Release: 写操作同步
// - AcqRel: 读写同步
// - SeqCst: 顺序一致(最强)
Send 和 Sync Trait
// Send: 类型的所有权可以跨线程转移
// Sync: 类型的引用可以跨线程共享(&T 是 Send 的)
// 几乎所有类型都是 Send 和 Sync 的
// 例外:Rc 不是 Send/Sync(使用 Arc)
// RefCell 不是 Sync(使用 Mutex)
// 裸指针不是 Send/Sync
// 手动实现(unsafe)
struct MyType {
ptr: *const i32,
}
unsafe impl Send for MyType {}
unsafe impl Sync for MyType {}
// 函数中的 Send 约束
fn spawn_task<T>(f: impl FnOnce() -> T + Send + 'static)
-> thread::JoinHandle<T>
where
T: Send + 'static,
{
thread::spawn(f)
}
Rayon - 数据并行
use rayon::prelude::*;
fn main() {
let numbers: Vec<i32> = (0..1_000_000).collect();
// 并行迭代(自动分块多线程处理)
let sum: i64 = numbers.par_iter()
.map(|&x| x as i64)
.sum();
// 并行 for_each
numbers.par_iter().for_each(|&x| {
// 并行处理每个元素
});
// 并行排序
let mut data = vec![3, 1, 4, 1, 5, 9, 2, 6];
data.par_sort_unstable();
// 配置线程池
use rayon::ThreadPoolBuilder;
let pool = ThreadPoolBuilder::new()
.num_threads(8)
.build()
.unwrap();
pool.install(|| {
numbers.par_iter().map(|x| x * 2).collect::<Vec<_>>()
});
}
18. 异步深入
▼
Future trait
// Future 是异步计算的核心抽象
use std::pin::Pin;
use std::task::{Context, Poll};
pub trait Future {
type Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
}
pub enum Poll<T> {
Ready(T),
Pending,
}
// async fn 返回实现了 Future 的类型
async fn hello() -> String {
String::from("Hello, world!")
}
// 等价于(编译器生成):
fn hello() -> impl Future<Output = String> {
async {
String::from("Hello, world!")
}
}
async/await 详解
use tokio;
// 基础异步函数
async fn fetch_data(url: &str) -> Result<String, reqwest::Error> {
let response = reqwest::get(url).await?;
response.text().await
}
// 异步闭包
let async_closure = async |x: i32| -> i32 {
// 异步操作
x * 2
};
// 异步块
let future = async {
let x = compute().await;
x + 1
};
// 并发执行多个异步任务
#[tokio::main]
async fn main() {
// tokio::join! - 并发等待多个 future
let (r1, r2, r3) = tokio::join!(
fetch_data("https://api1.example.com"),
fetch_data("https://api2.example.com"),
fetch_data("https://api3.example.com"),
);
// tokio::try_join! - 任一失败则提前返回
let result = tokio::try_join!(
fetch_data("https://api1.example.com"),
fetch_data("https://api2.example.com"),
);
// tokio::select! - 等待第一个完成的
let fastest = tokio::select! {
r1 = fetch_data("https://api1.example.com") => r1,
r2 = fetch_data("https://api2.example.com") => r2,
};
// spawn 创建新任务
let handle = tokio::spawn(async {
// 异步工作
42
});
let result = handle.await.unwrap();
// 超时
use tokio::time::{timeout, Duration};
let result = timeout(Duration::from_secs(5), fetch_data("https://api.example.com")).await;
match result {
Ok(Ok(data)) => println!("成功: {}", data),
Ok(Err(e)) => println!("失败: {}", e),
Err(_) => println!("超时"),
}
}
Stream trait(异步迭代器)
use futures::stream::{self, Stream, StreamExt};
// Stream 是 Future 的迭代版本
pub trait Stream {
type Item;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>)
-> Poll<Option<Self::Item>>;
}
async fn process_stream() {
// 创建 stream
let mut stream = stream::iter(1..=5);
// 消费 stream
while let Some(value) = stream.next().await {
println!("{}", value);
}
// 链式操作
let result: Vec<_> = stream::iter(1..=10)
.filter(|x| async { *x % 2 == 0 })
.map(|x| async { x * 2 })
.collect().await;
// channel 作为 stream
use tokio::sync::mpsc;
let (tx, mut rx) = mpsc::channel(100);
tokio::spawn(async move {
for i in 0..10 {
tx.send(i).await.unwrap();
}
});
while let Some(msg) = rx.recv().await {
println!("{}", msg);
}
}
Pin 和 Unpin
// Pin 确保值在内存中的位置不会改变
// 对于自引用的异步状态机是必需的
use std::pin::Pin;
// 大多数类型是 Unpin 的(可以在内存中移动)
// 例如:i32, String, Vec<T>, Box<T>
// 自引用结构体需要 Pin
struct SelfReferential {
value: String,
reference: *const String, // 指向 value
}
// 实现 !Unpin(不能移动)
use std::marker::PhantomPinned;
struct NotMovable {
value: String,
_pin: PhantomPinned,
}
// Pin::new 用于 Unpin 类型
let mut boxed = Box::new(5);
let pinned = Pin::new(&mut boxed);
// Pin::new_unchecked 用于非 Unpin 类型(需要保证不移动)
// Box::pin 创建堆上的 pinned 值
let pinned = Box::pin(NotMovable {
value: String::from("test"),
_pin: PhantomPinned,
});
异步运行时对比
| 运行时 | 特点 | 适用场景 |
|---|---|---|
| tokio | 最成熟,生态最丰富,多线程 | 大多数 Web 服务 |
| async-std | 标准库风格的 API | 学习、简单应用 |
| smol | 极简、轻量 | 嵌入式、小型工具 |
| glommio | 单线程、thread-per-core | 高性能数据库 |
| monoio | io_uring、thread-per-core | 极致性能场景 |
选择 tokio 的理由:
最丰富的生态(reqwest、sqlx、axum 等都基于 tokio),最活跃的社区,完善的多线程支持,生产环境久经考验。
19. Cargo 与生态
▼
Cargo 常用命令
# 项目管理
cargo new my_project # 创建新项目
cargo new --lib my_lib # 创建库项目
cargo init # 在当前目录初始化
cargo build # 编译
cargo build --release # 优化编译
cargo run # 编译并运行
cargo check # 快速类型检查(最快)
cargo test # 运行测试
cargo test -- --test-threads=1 # 单线程测试
cargo doc --open # 生成文档
cargo doc --no-deps # 不包含依赖文档
cargo clippy # 代码检查(lint)
cargo clippy --fix # 自动修复
cargo fmt # 代码格式化
cargo fmt -- --check # 检查是否已格式化
cargo bench # 性能测试
# 依赖管理
cargo add serde # 添加依赖
cargo add tokio --features full
cargo add serde --dev # dev-dependencies
cargo add serde --optional # 可选依赖
cargo remove serde # 移除依赖
cargo update # 更新依赖
cargo update -p serde # 更新特定依赖
cargo tree # 查看依赖树
cargo tree -d # 查看重复依赖
cargo outdated # 查看过期依赖(需安装)
# 工作区
cargo workspace # 管理工作区
# 发布
cargo login # 登录 crates.io
cargo publish --dry-run # 测试发布
cargo publish # 发布包
cargo yank --vers 1.0.0 # 撤回版本
# 工具
cargo install ripgrep # 安装全局工具
cargo uninstall ripgrep
cargo clean # 清理构建产物
cargo metadata # 输出元数据(JSON)
Cargo.toml 配置
# Cargo.toml 示例
[package]
name = "my_project"
version = "0.1.0"
edition = "2021"
authors = ["Your Name <you@example.com>"]
description = "A great project"
license = "MIT"
license-file = "LICENSE"
repository = "https://github.com/user/repo"
documentation = "https://docs.rs/my_project"
homepage = "https://example.com"
readme = "README.md"
keywords = ["cli", "tool"]
categories = ["command-line-utilities"]
exclude = ["/.github", "/tests"]
include = ["/src", "/Cargo.toml"]
publish = true # false 则不发布
rust-version = "1.70" # 最低 Rust 版本
[dependencies]
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
reqwest = { version = "0.11", features = ["json"], optional = true }
anyhow = "1.0"
thiserror = "1.0"
log = "0.4"
env_logger = "0.10"
local_crate = { path = "../local_crate" }
git_crate = { git = "https://github.com/user/repo", branch = "main" }
[dev-dependencies]
criterion = { version = "0.5", features = ["html_reports"] }
mockall = "0.11"
[build-dependencies]
cc = "1.0"
[[bench]]
name = "my_benchmark"
harness = false
[features]
default = ["std"]
std = []
json = ["serde", "reqwest"]
full = ["std", "json"]
[profile.dev]
opt-level = 0
debug = true
debug-assertions = true
overflow-checks = true
[profile.release]
opt-level = 3
debug = false
strip = true # 剥离符号
lto = true # 链接时优化
codegen-units = 1 # 最大化优化
panic = "abort" # 减少体积
incremental = false
[profile.test]
opt-level = 1
[workspace]
members = ["crate1", "crate2", "apps/*"]
exclude = ["legacy"]
# 别名
[alias]
b = "build --release"
t = "test"
r = "run"
c = "check"
工作区(Workspace)
# 根 Cargo.toml
[workspace]
members = [
"core",
"cli",
"web",
"common",
]
# 工作区级别的依赖配置(统一版本)
[workspace.dependencies]
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
anyhow = "1.0"
[workspace.package]
version = "0.1.0"
edition = "2021"
authors = ["Team"]
# 子包 Cargo.toml(如 core/Cargo.toml)
[package]
name = "my-core"
version.workspace = true
edition.workspace = true
[dependencies]
serde.workspace = true
anyhow.workspace = true
# 工作区命令
cargo build --workspace # 构建所有成员
cargo test --workspace
cargo clippy --workspace
cargo build -p my-core # 构建特定成员
常用 Crate 生态
| 类别 | Crate | 说明 |
|---|---|---|
| 序列化 | serde, serde_json, serde_yaml, toml | 序列化标准 |
| 异步 | tokio, async-std, futures | 异步运行时 |
| HTTP | reqwest, hyper, ureq | HTTP 客户端/服务器 |
| Web 框架 | axum, actix-web, rocket, warp | Web 开发 |
| 数据库 | sqlx, diesel, sea-orm, sled | 数据库访问 |
| 命令行 | clap, structopt | 参数解析 |
| 正则 | regex | 正则表达式 |
| 时间 | chrono, time | 日期时间 |
| 错误 | anyhow, thiserror | 错误处理 |
| 日志 | log, tracing, env_logger | 日志追踪 |
| 并行 | rayon, crossbeam | 并行计算 |
| 随机 | rand | 随机数 |
| 加密 | ring, rustls, sha2, aes-gcm | 密码学 |
| 压缩 | flate2, zip, tar | 压缩解压 |
| 图片 | image | 图片处理 |
| GUI | tauri, iced, egui | 图形界面 |
20. 测试进阶
▼
单元测试
// 在同一文件中的测试
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
pub fn divide(a: f64, b: f64) -> Result<f64, String> {
if b == 0.0 {
Err(String::from("除数为零"))
} else {
Ok(a / b)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(add(2, 3), 5);
assert_ne!(add(2, 3), 6);
assert!(add(2, 3) > 4);
}
#[test]
fn test_add_with_message() {
assert_eq!(add(2, 3), 5, "2 + 3 should equal 5");
}
#[test]
fn test_divide() {
assert_eq!(divide(10.0, 2.0), Ok(5.0));
assert!(divide(10.0, 0.0).is_err());
}
#[test]
fn test_with_result() -> Result<(), String> {
if 2 + 2 == 4 {
Ok(())
} else {
Err(String::from("math is broken"))
}
}
#[test]
#[should_panic(expected = "index out of bounds")]
fn test_should_panic() {
let v: Vec<i32> = vec![];
v[100];
}
#[test]
#[ignore]
fn expensive_test() {
// 耗时的测试
// cargo test -- --ignored 运行
}
#[tokio::test]
async fn test_async() {
let result = async { 42 }.await;
assert_eq!(result, 42);
}
}
# 运行测试命令
cargo test # 运行所有测试
cargo test test_add # 运行匹配名称的测试
cargo test -- --test-threads=1 # 单线程运行
cargo test -- --nocapture # 显示 println 输出
cargo test -- --ignored # 只运行 ignored 测试
cargo test -- --skip slow # 跳过名称含 slow 的测试
集成测试
// tests/integration_test.rs
// 每个文件是独立的 crate,只能访问公开的 API
use my_crate;
#[test]
fn test_public_api() {
assert_eq!(my_crate::add(2, 3), 5);
}
// tests/common/mod.rs - 共享测试辅助
pub fn setup() -> TestContext {
// 初始化测试环境
}
// tests/integration_test.rs
mod common;
#[test]
fn test_with_setup() {
let ctx = common::setup();
// 测试...
}
文档测试(Doc Tests)
/// 计算两数之和
///
/// # Examples
///
/// ```
/// let result = my_crate::add(2, 3);
/// assert_eq!(result, 5);
/// ```
///
/// # Panics
///
/// 不会 panic
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
/// 可能失败的示例
///
/// ```should_panic
/// panic!("this will panic");
/// ```
///
/// 隐藏部分代码
///
/// ```
/// # // 这行不会显示在文档中
/// # use my_crate::add;
/// assert_eq!(add(2, 3), 5);
/// ```
///
/// 不运行的代码
///
/// ```ignore
/// some_complex_code();
/// ```
///
/// 不编译的代码
///
/// ```compile_fail
/// let x: i32 = "not a number";
/// ```
///
/// 不测试的代码
///
/// ```no_run
/// loop_forever();
/// ```
pub fn documented_function() { }
# 运行文档测试
cargo test --doc
基准测试
// benches/my_benchmark.rs
use criterion::{criterion_group, criterion_main, Criterion, black_box};
fn fibonacci(n: u64) -> u64 {
match n {
0 => 0,
1 => 1,
_ => fibonacci(n - 1) + fibonacci(n - 2),
}
}
fn benchmark_fibonacci(c: &mut Criterion) {
c.bench_function("fib 20", |b| {
b.iter(|| fibonacci(black_box(20)))
});
}
// 参数化基准测试
fn benchmark_fibonacci_params(c: &mut Criterion) {
let mut group = c.benchmark_group("fibonacci");
for n in [10, 15, 20] {
group.bench_function(format!("fib {}", n), |b| {
b.iter(|| fibonacci(black_box(n)))
});
}
group.finish();
}
criterion_group!(benches, benchmark_fibonacci);
criterion_main!(benches);
# 运行基准测试
cargo bench
cargo bench -- --save-baseline master
cargo bench -- --baseline master # 与之前对比
测试辅助工具
// mockall - 自动生成 mock
use mockall::*;
#[automock]
trait Database {
fn get_user(&self, id: u32) -> Option<User>;
fn save_user(&self, user: &User) -> Result<(), Error>;
}
#[test]
fn test_with_mock() {
let mut mock_db = MockDatabase::new();
mock_db.expect_get_user()
.with(eq(1))
.returning(|_| Some(User { name: "Alice".into() }));
// 使用 mock_db...
}
// pretty_assertions - 更友好的 diff 显示
use pretty_assertions::{assert_eq, assert_ne};
// insta - 快照测试
use insta::assert_snapshot;
#[test]
fn test_snapshot() {
let output = generate_output();
assert_snapshot!(output);
}
# 更新快照
cargo insta review
覆盖率测试
# 安装 cargo-tarpaulin
cargo install cargo-tarpaulin
# 生成覆盖率报告
cargo tarpaulin --out Html
# 使用 grcov
cargo install grcov
export CARGO_INCREMENTAL=0
export RUSTFLAGS="-Cinstrument-coverage"
export LLVM_PROFILE_FILE="coverage-%p-%m.profraw"
cargo test
grcov . -s . --binary-path ./target/debug/ -t html --branch --ignore-not-existing -o ./coverage/
21. 宏
▼
声明式宏 (macro_rules!)
// 自定义 vec! 宏的简化版
#[macro_export]
macro_rules! vec {
( $( $x:expr ),* ) => {
{
let mut temp_vec = Vec::new();
$(
temp_vec.push($x);
)*
temp_vec
}
};
( $( $x:expr ),+ ) => {
{
let mut temp_vec = Vec::new();
$(
temp_vec.push($x);
)+
temp_vec
}
};
}
// 使用
let v = vec![1, 2, 3];
// 多模式匹配
macro_rules! calculate {
(eval $e:expr) => {
{
let val: usize = $e;
println!("{} = {}", stringify!($e), val);
}
};
(add $a:expr, $b:expr) => {
$a + $b
};
}
calculate!(eval 2 + 3);
let sum = calculate!(add 5, 10);
// 常见重复模式
macro_rules! hashmap {
( $( $key:expr => $value:expr ),* $(,)? ) => {
{
let mut map = std::collections::HashMap::new();
$(
map.insert($key, $value);
)*
map
}
};
}
let map = hashmap!{
"a" => 1,
"b" => 2,
"c" => 3,
};
宏的元变量类型
| 类型 | 匹配 |
|---|---|
| item | 任何项(函数、结构体、模块等) |
| block | 块 { ... } |
| stmt | 语句 |
| pat | 模式(Rust 2021+ 使用 pat_param) |
| expr | 表达式 |
| ty | 类型 |
| ident | 标识符 |
| path | 路径 a::b::c |
| tt | 单个 token tree(任意,最灵活) |
| meta | 属性内容 |
| lifetime | 生命周期 'a |
| literal | 字面量 |
| vis | 可见性修饰符 |
重复模式
// $()* - 零次或多次
// $()+ - 一次或多次
// $()? - 零次或一次
macro_rules! print_all {
( $( $x:expr ),* ) => {
$(
println!("{}", $x);
)*
};
}
print_all!("a", "b", "c");
// 嵌套重复
macro_rules! tuples {
( $( ( $( $x:expr ),* ) ),* ) => {
$(
$(
println!("{}", $x);
)*
)*
};
}
tuples!((1, 2), (3, 4, 5));
过程宏(Procedural Macros)
// 过程宏必须在单独的 crate 中定义
// Cargo.toml:
# [lib]
# proc-macro = true
# [dependencies]
# syn = "2.0"
# quote = "1.0"
# proc-macro2 = "1.0"
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
// 1. 派生宏(derive)
#[proc_macro_derive(MyMacro)]
pub fn my_macro_derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = &input.ident;
let expanded = quote! {
impl #name {
fn my_method(&self) -> String {
format!("Hello from {}!", stringify!(#name))
}
}
};
expanded.into()
}
// 使用:
#[derive(MyMacro)]
struct MyStruct;
// 2. 属性宏
#[proc_macro_attribute]
pub fn route(attr: TokenStream, item: TokenStream) -> TokenStream {
// attr: GET, "/"
// item: fn index() { ... }
item
}
#[route(GET, "/")]
fn index() { }
// 3. 函数宏
#[proc_macro]
pub fn sql(input: TokenStream) -> TokenStream {
// 解析 SQL 并生成代码
input
}
常用内置宏
fn main() {
// 输出
println!("{} {}", "hello", "world");
eprintln!("error!");
print!("no newline");
// 格式化字符串
let s = format!("Hello, {}!", "Rust");
let s = format_args!("{}", 42);
// 创建集合
let v = vec![1, 2, 3];
// 断言
assert!(true);
assert_eq!(1 + 1, 2);
assert_ne!(1, 2);
debug_assert!(1 == 1); // 只在 debug 构建
// panic
// panic!("error: {}", 42);
// 编译时信息
// compile_error!("This feature is not supported");
// 其他
let file = file!();
let line = line!();
let col = column!();
let module = module_path!();
let str = stringify!(some expression);
todo!(); // 标记未完成代码
unimplemented!();
unreachable!();
let x = dbg!(2 * 3); // 打印并返回值
// 配置
#[cfg(target_os = "linux")]
fn linux_only() { }
// cfg! 宏(运行时)
if cfg!(target_os = "linux") {
println!("Running on Linux");
}
// env! 宏(编译时环境变量)
let target = env!("TARGET");
let default = option_env!("OPTIONAL").unwrap_or("default");
// include! 宏
// include!("other.rs");
// include_str!("file.txt");
// include_bytes!("file.bin");
}
22. Unsafe Rust
▼
什么是 Unsafe
Rust 的 safe 代码无法实现某些底层操作时使用 unsafe。它不会关闭借用检查器,而是提供额外的能力:
裸指针
fn main() {
let mut num = 5;
// 创建裸指针(safe)
let r1 = &num as *const i32;
let r2 = &mut num as *mut i32;
// 解引用需要 unsafe
unsafe {
println!("r1: {}", *r1);
println!("r2: {}", *r2);
*r2 = 10;
println!("r2 after: {}", *r2);
}
// 指向任意内存地址
let address = 0x12345usize;
let r = address as *const i32;
// unsafe { *r } // 可能访问无效内存
// 裸指针方法
let p: *const i32 = #
let mut mp: *mut i32 = &mut num;
p.is_null();
p.as_ref(); // unsafe,返回 Option
mp.as_mut();
p.offset(1); // unsafe,指针运算
mp.add(1); // unsafe
mp.sub(1);
mp.write(42); // unsafe
p.read(); // unsafe
p.copy_to(mp, 1); // unsafe
p.copy_to_nonoverlapping(mp, 1);
}
Unsafe 函数
// 定义 unsafe 函数
unsafe fn dangerous() {
println!("This is unsafe!");
}
// 调用需要 unsafe 块
unsafe {
dangerous();
}
// 安全抽象包装(最常见用法)
fn safe_wrapper() {
// 维护安全不变量
unsafe {
dangerous();
}
}
// split_at_mut 的安全实现(标准库中的例子)
fn split_at_mut<T>(slice: &mut [T], mid: usize) -> (&mut [T], &mut [T]) {
let len = slice.len();
let ptr = slice.as_mut_ptr();
assert!(mid <= len);
unsafe {
(
std::slice::from_raw_parts_mut(ptr, mid),
std::slice::from_raw_parts_mut(ptr.add(mid), len - mid),
)
}
}
// 调用外部 C 函数 (FFI)
extern "C" {
fn abs(input: i32) -> i32;
fn malloc(size: usize) -> *mut std::ffi::c_void;
fn free(ptr: *mut std::ffi::c_void);
}
fn main() {
unsafe {
println!("abs(-3): {}", abs(-3));
}
}
// 导出 Rust 函数给 C 调用
#[no_mangle]
pub extern "C" fn rust_function(x: i32) -> i32 {
x * 2
}
静态变量与 Trait
// 可变静态变量
static mut COUNTER: u32 = 0;
fn add_to_count(inc: u32) {
unsafe {
COUNTER += inc;
}
}
fn get_counter() -> u32 {
unsafe {
COUNTER
}
}
// Unsafe trait
unsafe trait Foo {
fn method(&self);
}
unsafe impl Foo for i32 {
fn method(&self) {
println!("{}", self);
}
}
// Union (共用体,类似 C 的 union)
union MyUnion {
f1: u32,
f2: f32,
}
fn main() {
let u = MyUnion { f1: 42 };
unsafe {
println!("{}", u.f1);
}
// 使用 match 安全访问
fn get_value(u: MyUnion) {
unsafe {
match u {
MyUnion { f1 } => println!("u32: {}", f1),
}
}
}
}
使用原则:
安全文档示例
/// 从指针读取值
///
/// # Safety
///
/// 调用者必须保证:
/// - 指针非空
/// - 指针指向有效的、已初始化的 T 类型数据
/// - 指针具有正确的对齐
pub unsafe fn read_value<T>(ptr: *const T) -> T {
// 调用者保证安全,此处直接读取
*ptr
}
23. FFI 外部函数接口
▼
调用 C 库
use std::ffi::{CStr, CString};
use std::os::raw::{c_int, c_char, c_void};
// 声明 C 函数
extern "C" {
fn puts(s: *const c_char) -> c_int;
fn strlen(s: *const c_char) -> usize;
fn malloc(size: usize) -> *mut c_void;
fn free(ptr: *mut c_void);
fn abs(n: c_int) -> c_int;
}
fn main() {
unsafe {
// Rust 字符串转 C 字符串
let s = CString::new("Hello from Rust!").unwrap();
puts(s.as_ptr());
// C 字符串转 Rust 字符串
let c_str = CStr::from_ptr(s.as_ptr());
let rust_str = c_str.to_str().unwrap();
println!("{}", rust_str);
// 使用 malloc/free
let ptr = malloc(std::mem::size_of::<i32>()) as *mut i32;
*ptr = 42;
println!("{}", *ptr);
free(ptr as *mut c_void);
println!("abs(-5): {}", abs(-5));
}
}
使用 bindgen 自动生成绑定
# 安装 bindgen
cargo install bindgen-cli
# 生成绑定
bindgen wrapper.h -o bindings.rs
# 在 build.rs 中使用
use std::env;
use std::path::PathBuf;
fn main() {
// 告诉 cargo 链接 C 库
println!("cargo:rustc-link-lib=mylib");
println!("cargo:rustc-link-search=native=/path/to/lib");
// 使用 bindgen 生成绑定
let bindings = bindgen::Builder::default()
.header("wrapper.h")
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
.generate()
.expect("Unable to generate bindings");
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
}
导出 Rust 函数给 C 使用
// lib.rs
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
// #[no_mangle] 防止编译器修改符号名
#[no_mangle]
pub extern "C" fn rust_add(a: i32, b: i32) -> i32 {
a + b
}
#[no_mangle]
pub extern "C" fn rust_greet(name: *const c_char) -> *mut c_char {
let name = unsafe { CStr::from_ptr(name) };
let name = name.to_str().unwrap_or("stranger");
let greeting = format!("Hello, {}!", name);
let c_string = CString::new(greeting).unwrap();
c_string.into_raw() // 转移所有权给 C
}
// 提供释放函数
#[no_mangle]
pub extern "C" fn rust_free_string(s: *mut c_char) {
if s.is_null() { return; }
unsafe {
CString::from_raw(s); // 重新获取所有权并 drop
}
}
// 导出不透明类型
pub struct MyObject {
value: i32,
}
#[no_mangle]
pub extern "C" fn my_object_new(value: i32) -> *mut MyObject {
Box::into_raw(Box::new(MyObject { value }))
}
#[no_mangle]
pub extern "C" fn my_object_get_value(obj: *const MyObject) -> i32 {
unsafe { (*obj).value }
}
#[no_mangle]
pub extern "C" fn my_object_free(obj: *mut MyObject) {
if !obj.is_null() {
unsafe {
let _ = Box::from_raw(obj);
}
}
}
C 与 Rust 类型对照
| C 类型 | Rust 类型 |
|---|---|
| int | std::os::raw::c_int (i32) |
| unsigned int | std::os::raw::c_uint (u32) |
| long | std::os::raw::c_long |
| char | std::os::raw::c_char (i8) |
| char* | mut c_char / const c_char |
| const char* | *const c_char |
| void* | *mut c_void |
| size_t | usize |
| ssize_t | isize |
| int32_t | i32 |
| uint64_t | u64 |
| bool | bool 或 std::os::raw::c_uchar |
推荐工具:
24. 设计模式
▼
Builder 模式
struct HttpRequest {
url: String,
method: String,
headers: Vec<(String, String)>,
body: Option<String>,
timeout: u64,
}
struct HttpRequestBuilder {
url: String,
method: String,
headers: Vec<(String, String)>,
body: Option<String>,
timeout: u64,
}
impl HttpRequestBuilder {
fn new(url: &str) -> Self {
Self {
url: url.to_string(),
method: "GET".to_string(),
headers: Vec::new(),
body: None,
timeout: 30,
}
}
fn method(mut self, method: &str) -> Self {
self.method = method.to_string();
self
}
fn header(mut self, key: &str, value: &str) -> Self {
self.headers.push((key.to_string(), value.to_string()));
self
}
fn body(mut self, body: &str) -> Self {
self.body = Some(body.to_string());
self
}
fn timeout(mut self, seconds: u64) -> Self {
self.timeout = seconds;
self
}
fn build(self) -> HttpRequest {
HttpRequest {
url: self.url,
method: self.method,
headers: self.headers,
body: self.body,
timeout: self.timeout,
}
}
}
let request = HttpRequestBuilder::new("https://api.example.com")
.method("POST")
.header("Content-Type", "application/json")
.body(r#"{"key":"value"}"#)
.timeout(60)
.build();
Newtype 模式
// 为第三方类型实现第三方 trait
struct Wrapper(Vec<String>);
impl std::fmt::Display for Wrapper {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "[{}]", self.0.join(", "))
}
}
// 类型安全(区分不同语义的相同类型)
struct Meters(f64);
struct Millimeters(f64);
struct Seconds(f64);
// 不能混合使用
// let distance = Meters(100.0) + Millimeters(50.0); // 编译错误
impl Meters {
fn to_millimeters(self) -> Millimeters {
Millimeters(self.0 * 1000.0)
}
}
// 邮箱类型验证
struct Email(String);
impl Email {
fn new(s: String) -> Result<Self, &'static str> {
if s.contains('@') {
Ok(Email(s))
} else {
Err("Invalid email")
}
}
fn as_str(&self) -> &str {
&self.0
}
}
Typestate 模式
// 使用类型系统防止无效状态
struct Draft;
struct PendingReview;
struct Published;
struct Post<State> {
content: String,
_state: std::marker::PhantomData<State>,
}
impl Post<Draft> {
fn new() -> Self {
Post {
content: String::new(),
_state: std::marker::PhantomData,
}
}
fn add_text(&mut self, text: &str) {
self.content.push_str(text);
}
fn request_review(self) -> Post<PendingReview> {
Post {
content: self.content,
_state: std::marker::PhantomData,
}
}
}
impl Post<PendingReview> {
fn approve(self) -> Post<Published> {
Post {
content: self.content,
_state: std::marker::PhantomData,
}
}
}
impl Post<Published> {
fn content(&self) -> &str {
&self.content
}
}
fn main() {
let mut post = Post::new();
post.add_text("Hello world");
// post.content(); // 编译错误!Draft 状态没有 content 方法
let post = post.request_review();
// post.content(); // 编译错误!PendingReview 也没有
let post = post.approve();
println!("{}", post.content()); // OK
}
RAII 模式
// Rust 自动使用 RAII(资源获取即初始化)
// 文件自动关闭
use std::fs::File;
use std::io::Write;
fn write_to_file() -> std::io::Result<()> {
let mut file = File::create("test.txt")?;
file.write_all("Hello".as_bytes())?;
Ok(())
} // file 自动关闭
// 锁自动释放
use std::sync::Mutex;
let m = Mutex::new(0);
{
let mut guard = m.lock().unwrap();
*guard += 1;
} // 锁自动释放
// 自定义 RAII 类型
struct Timer {
start: std::time::Instant,
name: String,
}
impl Timer {
fn new(name: &str) -> Self {
Self {
start: std::time::Instant::now(),
name: name.to_string(),
}
}
}
impl Drop for Timer {
fn drop(&mut self) {
println!("{} took {:?}", self.name, self.start.elapsed());
}
}
fn expensive_operation() {
let _timer = Timer::new("expensive_operation");
// 执行操作...
} // 自动打印耗时
State 模式
// 使用 trait object 实现状态模式
trait State {
fn request_review(self: Box<dyn State>) -> Box<dyn State>;
fn approve(self: Box<dyn State>) -> Box<dyn State>;
fn content<'a>(self: &'a Box<dyn State>, post: &'a Post) -> &'a str {
""
}
}
struct Draft;
impl State for Draft {
fn request_review(self: Box<dyn State>) -> Box<dyn State> {
Box::new(PendingReview)
}
fn approve(self: Box<dyn State>) -> Box<dyn State> {
self
}
}
struct PendingReview;
impl State for PendingReview {
fn request_review(self: Box<dyn State>) -> Box<dyn State> {
self
}
fn approve(self: Box<dyn State>) -> Box<dyn State> {
Box::new(Published)
}
}
struct Published;
impl State for Published {
fn request_review(self: Box<dyn State>) -> Box<dyn State> {
self
}
fn approve(self: Box<dyn State>) -> Box<dyn State> {
self
}
fn content<'a>(self: &'a Box<dyn State>, post: &'a Post) -> &'a str {
&post.content
}
}
pub struct Post {
state: Option<Box<dyn State>>,
content: String,
}
impl Post {
pub fn new() -> Post {
Post {
state: Some(Box::new(Draft)),
content: String::new(),
}
}
pub fn add_text(&mut self, text: &str) {
self.content.push_str(text);
}
pub fn request_review(&mut self) {
if let Some(s) = self.state.take() {
self.state = Some(s.request_review());
}
}
pub fn approve(&mut self) {
if let Some(s) = self.state.take() {
self.state = Some(s.approve());
}
}
pub fn content(&self) -> &str {
self.state.as_ref().unwrap().content(self)
}
}
25. 内存布局
▼
类型大小与对齐
use std::mem;
fn main() {
// 类型大小
println!("bool: {} bytes", mem::size_of::<bool>()); // 1
println!("i32: {} bytes", mem::size_of::<i32>()); // 4
println!("i64: {} bytes", mem::size_of::<i64>()); // 8
println!("char: {} bytes", mem::size_of::<char>()); // 4
println!("&str: {} bytes", mem::size_of::<&str>()); // 16 (指针 + 长度)
println!("String: {} bytes", mem::size_of::<String>()); // 24 (指针 + 长度 + 容量)
println!("Vec<T>: {} bytes", mem::size_of::<Vec<i32>>()); // 24
println!("Option<i32>: {}", mem::size_of::<Option<i32>>()); // 8
println!("Option<&i32>: {}", mem::size_of::<Option<&i32>>()); // 8(指针优化)
// 对齐
println!("i32 align: {}", mem::align_of::<i32>()); // 4
println!("i64 align: {}", mem::align_of::<i64>()); // 8
// 结构体布局
struct A {
a: u8,
b: u32,
c: u8,
}
println!("A size: {}", mem::size_of::<A>()); // 12 (有填充)
// 重排字段顺序减少填充
struct B {
b: u32,
a: u8,
c: u8,
}
println!("B size: {}", mem::size_of::<B>()); // 8 (更紧凑)
// 字段偏移
println!("A.b offset: {}", mem::offset_of!(A, b));
// 交换
let mut x = 5;
let mut y = 10;
mem::swap(&mut x, &mut y);
// 替换
let old = mem::replace(&mut x, 20);
// take(替换为默认值)
let old = mem::take(&mut x);
// 忘记 drop(危险!)
// mem::forget(value);
// 零初始化
// let x: i32 = mem::zeroed(); // unsafe in modern Rust
let x: MaybeUninit<i32> = MaybeUninit::zeroed();
}
use std::mem::MaybeUninit;
// 安全使用 MaybeUninit
let mut x = MaybeUninit::<i32>::uninit();
x.write(42);
let x = unsafe { x.assume_init() };
repr 属性
// 控制数据布局
// C 兼容布局(保证与 C 结构体一致)
#[repr(C)]
struct CStruct {
a: u8,
b: u32,
c: u8,
}
// 保证字段顺序不变,有对齐填充
// 紧凑布局(无填充)
#[repr(packed)]
struct Packed {
a: u8,
b: u32,
c: u8,
}
println!("Packed size: {}", mem::size_of::<Packed>()); // 6
// 特定对齐
#[repr(align(16))]
struct Aligned {
data: [u8; 4],
}
println!("Aligned: size={}, align={}",
mem::size_of::<Aligned>(),
mem::align_of::<Aligned>()); // 16, 16
// 透明包装(Newtype 不影响布局)
#[repr(transparent)]
struct Wrapper(i32);
// 保证与 i32 完全相同的布局和 ABI
// Rust 默认布局(可重排字段)
#[repr(Rust)] // 默认
struct Default {
a: u8,
b: u32,
c: u8,
}
// 枚举布局
#[repr(C)]
enum CEnum { A, B, C }
#[repr(u8)]
enum SmallEnum { A, B, C } // 使用 1 字节表示
// C 兼容的枚举 + 数据
#[repr(C)]
enum Tagged {
A { x: i32 },
B(f64),
}
指针大小
// 不同类型引用的大小
println!("&i32: {}", mem::size_of::<&i32>()); // 8 (64-bit)
println!("&str: {}", mem::size_of::<&str>()); // 16 (胖指针:指针+长度)
println!("&[i32]: {}", mem::size_of::<&[i32]>()); // 16 (胖指针)
println!("&dyn Trait: {}", mem::size_of::<&dyn std::fmt::Display>()); // 16 (指针+vtable)
// 动态大小类型 (DST)
// str, [T], dyn Trait 都是 DST
// 不能直接拥有,必须通过引用或 Box
let s: &str = "hello"; // OK
let b: Box<str> = Box::from("hello"); // OK
// let s: str = "hello"; // 错误!
26. 条件编译
▼
cfg 属性
// 按操作系统
#[cfg(target_os = "linux")]
fn linux_only() { }
#[cfg(target_os = "windows")]
fn windows_only() { }
#[cfg(target_os = "macos")]
fn macos_only() { }
#[cfg(any(target_os = "linux", target_os = "macos"))]
fn unix_like() { }
// 按架构
#[cfg(target_arch = "x86_64")]
fn x86_64_only() { }
#[cfg(target_arch = "aarch64")]
fn arm_only() { }
#[cfg(target_arch = "wasm32")]
fn wasm_only() { }
// 按构建类型
#[cfg(debug_assertions)]
fn debug_only() { }
#[cfg(not(debug_assertions))]
fn release_only() { }
// 按特性(feature)
#[cfg(feature = "json")]
fn json_feature() { }
#[cfg(all(feature = "json", feature = "async"))]
fn both_features() { }
// 按测试
#[cfg(test)]
mod tests { }
// 自定义条件
#[cfg(my_custom_condition)]
fn custom() { }
# 编译时启用:rustc --cfg my_custom_condition
// cfg! 宏(运行时检查)
if cfg!(target_os = "linux") {
println!("Running on Linux");
} else {
println!("Not Linux");
}
// 常用 target_* 配置
// target_os: "linux", "windows", "macos", "ios", "android", "freebsd"
// target_arch: "x86", "x86_64", "arm", "aarch64", "wasm32", "riscv64"
// target_family: "unix", "windows"
// target_env: "gnu", "msvc", "musl"
// target_endian: "little", "big"
// target_pointer_width: "32", "64"
Feature Flags
# Cargo.toml
[features]
default = ["std"]
std = []
json = ["serde", "serde_json"]
async = ["tokio"]
full = ["std", "json", "async"]
# 可选依赖作为 feature
[dependencies]
serde = { version = "1.0", optional = true }
serde_json = { version = "1.0", optional = true }
tokio = { version = "1", optional = true }
# 在代码中使用
#[cfg(feature = "json")]
use serde::{Serialize, Deserialize};
#[cfg(feature = "json")]
pub fn to_json<T: Serialize>(value: &T) -> String {
serde_json::to_string(value).unwrap()
}
# 构建时启用 features
cargo build --features json
cargo build --features "json async"
cargo build --no-default-features
cargo build --all-features
Build Scripts
# build.rs - 在编译前运行
use std::env;
use std::path::Path;
fn main() {
// 告诉 cargo 重新运行条件
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=src/data.txt");
// 设置环境变量
println!("cargo:rustc-env=BUILD_TIME={}", chrono::Utc::now());
// 链接库
println!("cargo:rustc-link-lib=sqlite3");
println!("cargo:rustc-link-search=native=/usr/lib");
// 条件编译标志
println!("cargo:rustc-cfg=has_openssl");
# 生成代码
let out_dir = env::var("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("generated.rs");
std::fs::write(dest_path, "pub const VERSION: &str = \"1.0.0\";").unwrap();
# 编译 C/C++ 代码
# cc::Build::new()
# .file("src/native.c")
# .compile("native");
}
# 使用生成的代码
include!(concat!(env!("OUT_DIR"), "/generated.rs"));
27. 最佳实践
▼
代码风格与规范
// 使用 rustfmt 统一风格
// 使用 clippy 检查代码质量
// 变量命名:snake_case
let user_name = "Alice";
let max_retry_count = 3;
// 类型命名:PascalCase
struct UserProfile { }
enum ConnectionState { }
// 函数命名:snake_case
fn calculate_total() { }
fn is_valid() -> bool { }
// 常量:SCREAMING_SNAKE_CASE
const MAX_CONNECTIONS: usize = 100;
const DEFAULT_TIMEOUT: u64 = 30;
// 生命周期:单个小写字母
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { }
// Trait 命名:PascalCase
trait Drawable { }
trait Iterator { }
错误处理最佳实践
// 1. 库代码:返回具体的 Result
pub fn parse_config(content: &str) -> Result<Config, ConfigError> {
// ...
}
// 2. 应用代码:使用 anyhow
use anyhow::{Result, Context};
fn main() -> Result<()> {
let config = parse_config(&content)
.context("failed to parse config")?;
Ok(())
}
// 3. 避免 unwrap 在生产代码
// 使用 expect 提供信息
let value = opt.expect("配置项 'foo' 必须存在");
// 4. 提供上下文
let file = File::open(path)
.with_context(|| format!("failed to open {}", path.display()))?;
性能优化建议
use std::hint::{unlikely, black_box};
fn process(x: i32) -> i32 {
if unlikely(x < 0) {
// 很少发生的错误路径
return -1;
}
// 常见路径
x * 2
}
项目结构建议
my_project/
├── Cargo.toml
├── Cargo.lock
├── README.md
├── LICENSE
├── CHANGELOG.md
├── .gitignore
├── src/
│ ├── main.rs # 二进制入口(尽量薄)
│ ├── lib.rs # 库入口(导出公共 API)
│ ├── config/
│ │ ├── mod.rs
│ │ └── settings.rs
│ ├── models/
│ │ ├── mod.rs
│ │ ├── user.rs
│ │ └── order.rs
│ ├── services/
│ │ ├── mod.rs
│ │ └── auth.rs
│ ├── errors.rs # 统一错误定义
│ ├── utils.rs
│ └── prelude.rs # 常用导入
├── tests/
│ ├── common/
│ │ └── mod.rs
│ └── integration_tests.rs
├── benches/
│ └── performance.rs
├── examples/
│ └── basic_usage.rs
├── migrations/
│ └── 001_create_users.sql
└── docs/
└── architecture.md
常用工具链
| 工具 | 用途 |
|---|---|
| rustup | Rust 版本管理 |
| cargo | 构建和包管理 |
| rustfmt | 代码格式化 |
| clippy | 代码静态分析 |
| rust-analyzer | IDE 支持(VSCode 推荐) |
| cargo-watch | 文件监控自动重新编译 |
| cargo-expand | 展开宏查看生成代码 |
| cargo-flamegraph | 性能分析火焰图 |
| cargo-audit | 检查依赖的安全漏洞 |
| cargo-deny | 检查许可证和依赖 |
| cargo-nextest | 更快的测试运行器 |
| cargo-tarpaulin | 代码覆盖率 |
| cargo-edit | 命令行编辑依赖 |
学习资源推荐
官方资源:
• 《The Rust Programming Language》(TRPL) - 官方入门书
• 《Rust by Example》 - 通过示例学习
• 《Rustlings》 - 小练习集
• 《Rust Reference》 - 语言参考
• 《The Cargo Book》 - Cargo 手册
• 《The Rustonomicon》 - Unsafe Rust 指南
• crates.io - 包仓库
• docs.rs - 文档
进阶书籍:
• 《Programming Rust》(O'Reilly) - 深入系统编程
• 《Rust for Rustaceans》 - 中级到高级
• 《Asynchronous Programming in Rust》 - 异步专题
• 《Zero To Production In Rust》 - 后端开发实战
实践项目:
• 实现一个 HTTP 服务器
• 实现一个 JSON 解析器
• 实现一个解释器
• 重写一个 Unix 工具(ls, grep, cat)
• 实现一个数据库存储引擎
Rust 2024 Edition 新特性
# 使用 Rust 2024 Edition
[package]
edition = "2024"
// 主要变化:
// 1. 更严格的 unsafe extern 块
unsafe extern "C" {
fn c_function();
}
// 2. RPITIT(Return Position Impl Trait In Traits)
trait Iterator {
fn filter<P>(self, predicate: P) -> impl Iterator<Item = Self::Item>;
}
// 3. 更严格的 never type 行为
// 4. Prelude 变化
// 5. 生命周期捕获规则改进
# 迁移工具
cargo fix --edition
没有找到相关内容