Rust 语言教程 - 完整指南(增强版)

IT 技术 99 阅读 更新于 2026-09-25 17:41

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-biti8u8-128 ~ 127 / 0 ~ 255
16-biti16u16-32768 ~ 32767 / 0 ~ 65535
32-biti32u32-2^31 ~ 2^31-1
64-biti64u64-2^63 ~ 2^63-1
128-biti128u128-2^127 ~ 2^127-1
架构isizeusize随指针大小变化
// 整数类型
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 的核心特性,在编译时管理内存,无需垃圾回收:

  1. 每个值有且只有一个所有者(Owner)
  2. 同一时刻只能有一个所有者
  3. 当所有者离开作用域,值被丢弃(Drop)
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 的所有权至关重要:

  • 栈(Stack):固定大小的数据,LIFO 访问,速度快
  • 堆(Heap):动态大小的数据,需要分配器管理,速度较慢

String 由三部分组成(都在栈上):

  • 指向堆上数据的指针
  • 长度(length)- 当前使用的字节数
  • 容量(capacity)- 已分配的总字节数
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 类型

  • Box<T> - 释放堆内存
  • Vec<T> - 释放堆内存 + 递归 drop 元素
  • String - 释放堆内存
  • File - 关闭文件句柄
  • Mutex<T> - 释放锁
  • TcpStream - 关闭网络连接

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. 字符串深入

▼

字符串类型区别

类型说明所有权可变
StringUTF-8 字符串,堆分配拥有可变
&str字符串切片,UTF-8借用不可变
&mut str可变字符串切片(很少用)借用可变
OsString操作系统原生字符串拥有可变
&OsStr操作系统字符串切片借用不可变
PathBuf路径,堆分配拥有可变
&Path路径切片借用不可变
CStringC 兼容的字符串(\0 结尾)拥有可变
&CStrC 字符串切片借用不可变

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 已失效
}

生命周期省略规则

编译器会自动推断一些常见情况:

  1. 每个引用参数获得自己的生命周期参数
  2. 如果只有一个输入生命周期参数,它被赋给所有输出
  3. 如果有 &self 或 &mut self,self 的生命周期被赋给所有输出
// 编译器自动推断(不需要标注)
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高性能数据库
monoioio_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异步运行时
HTTPreqwest, hyper, ureqHTTP 客户端/服务器
Web 框架axum, actix-web, rocket, warpWeb 开发
数据库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图片处理
GUItauri, 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。它不会关闭借用检查器,而是提供额外的能力:

  • 解引用裸指针
  • 调用 unsafe 函数或方法
  • 访问或修改可变的静态变量
  • 实现 unsafe trait
  • 访问 union 的字段

裸指针

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),
            }
        }
    }
}

使用原则:

  • 只在必要时使用 unsafe
  • 用 safe 抽象包裹 unsafe 代码
  • 文档说明安全约束条件(# Safety 章节)
  • 尽量缩小 unsafe 块的范围
  • 提供安全的公共 API

安全文档示例

/// 从指针读取值
///
/// # 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 类型
intstd::os::raw::c_int (i32)
unsigned intstd::os::raw::c_uint (u32)
longstd::os::raw::c_long
charstd::os::raw::c_char (i8)
char*mut c_char / const c_char
const char**const c_char
void**mut c_void
size_tusize
ssize_tisize
int32_ti32
uint64_tu64
boolbool 或 std::os::raw::c_uchar

推荐工具:

  • bindgen:自动生成 C 头文件的 Rust 绑定
  • cbindgen:从 Rust 代码生成 C 头文件
  • cc crate:在 build.rs 中编译 C/C++ 代码

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()))?;

性能优化建议

  • 优先使用迭代器而非手写循环(编译器可更好优化)
  • 避免不必要的 clone(),使用引用或 Cow
  • 使用 String::with_capacity() 预分配
  • 使用 Vec::with_capacity() 避免重新分配
  • 使用 rayon 进行并行计算
  • Profile 后再优化,避免过早优化
  • 使用 Box<[T]> 或 Vec 处理动态大小的集合
  • 使用 smallvec crate 避免小集合的堆分配
  • 使用 hashbrown 或 ahash 替代默认 HashMap(更快)
  • 使用 parking_lot 替代标准 Mutex(更快)
  • 使用 once_cell / LazyLock 替代 lazy_static
  • 避免在热路径上使用动态分发(dyn Trait)
  • 使用 #[inline] 内联关键函数
  • 使用 likely() / unlikely() 优化分支预测
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

常用工具链

工具用途
rustupRust 版本管理
cargo构建和包管理
rustfmt代码格式化
clippy代码静态分析
rust-analyzerIDE 支持(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

没有找到相关内容

← 返回IT 技术 yicool 百科 · Rust 语言教程 - 完整指南(增强版)

评论 0