Rust 教程

什么是 Rust?

Rust 是由 Mozilla 主导开发(现由 Rust 基金会维护)的系统级编程语言,2015 年发布 1.0。它以内存安全与高性能著称,连续多年被评为"最受喜爱的编程语言"。

Rust 的核心特点

  • 内存安全:所有权(Ownership)系统在编译期杜绝空指针、悬垂引用、数据竞争
  • 零成本抽象:高级语言体验,接近 C/C++ 的性能
  • 无垃圾回收:内存由所有权机制自动管理
  • 并发安全:Send/Sync 特性保证线程安全
  • 工具链完善:Cargo 包管理、rustfmt 格式化、clippy 检查

Rust 能做什么

  • 系统软件:操作系统、驱动、嵌入式
  • 高性能服务:Web 后端(Axum/Actix)、网络代理
  • 命令行工具(ripgrep、fd、bat 都是 Rust 写的)
  • 区块链与智能合约
  • WebAssembly 前端

Hello World

fn main() {
    println!("Hello, world!");
}
# 编译运行
rustc hello.rs
./hello

# 或使用 Cargo
cargo new hello
cargo run

Rust 简介

Rust 简介

Rust 的设计目标是在不牺牲性能的前提下提供内存安全,其核心创新是所有权系统。

Rust 的诞生

2006  Graydon Hoare 个人项目
2009  Mozilla 资助
2015  1.0 发布
2016+ 连续多年最受欢迎语言
2021  Rust 基金会成立
2023+ Windows/Linux 内核开始接纳 Rust

核心设计理念

1. 安全优先:
   编译期捕获大多数内存错误
   C 语言常见 bug(use-after-free、缓冲区溢出)在 Rust 中无法编译通过

2. 性能优先:
   无 GC、无运行时开销
   零成本抽象: 高级语法编译成高效机器码

3. 并发安全:
   Send + Sync 特性由编译器验证
   数据竞争在编译期就被拒绝

Rust vs 其他语言

vs C/C++:
  Rust 提供了 C 的性能,但内存安全由编译器保证
  Cargo 让依赖管理像 npm/pip 一样简单

vs Go:
  Go 简单易学、有 GC;Rust 更精细控制、性能更高
  两者在服务端都常用

vs Python:
  Python 开发快;Rust 性能强
  Rust 常用来给 Python 写高性能扩展

生态概览

包管理:  Cargo + crates.io(100 万+ crate)
Web:      Axum、Actix-web、Rocket
异步:     Tokio、async-std
数据库:   sqlx、Diesel、sea-orm
序列化:   serde
测试:     内置 + proptest
LSP:      rust-analyzer

适合人群

- 系统/嵌入式开发者
- 追求性能的 Web 后端
- CLI 工具开发者
- 对内存安全要求高的团队
- 想理解现代编译期安全机制的学习者

Rust 环境搭建

Rust 环境搭建

安装 Rust 推荐使用 rustup 工具链管理器,一条命令搞定。

1. 安装 rustup

# macOS / Linux
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Windows
下载 rustup-init.exe 安装

# 安装完成后配置 PATH(一般自动)
source "$HOME/.cargo/env"

2. 验证安装

rustc --version      # 编译器版本
cargo --version      # 包管理版本
rustup --version     # 工具链管理器

3. 更新与卸载

rustup update        # 更新工具链
rustup self uninstall  # 卸载
rustup show          # 查看已安装组件

4. 安装 IDE 插件

VS Code:
  1. rust-analyzer 插件(语言支持)
  2. Even Better TOML(配置高亮)
  3. crates(依赖版本提示)

IntelliJ:
  Rust 插件

# 安装 rust-analyzer 命令行
rustup component add rust-analyzer

5. 第一个 Cargo 项目

# 新建项目
cargo new hello_world
cd hello_world

# 目录结构
# hello_world/
# ├── Cargo.toml   # 项目配置
# └── src/
#     └── main.rs  # 源码

# 编译并运行
cargo run

# 仅编译
cargo build

# 发布模式(优化)
cargo build --release

6. 常见问题

1. 编译慢: 首次编译依赖多,正常;release 更慢
2. 依赖下载慢: 配置国内镜像(rsproxy.cn)
3. Windows 链接错误: 安装 Visual Studio Build Tools
4. rustc 找不到: source ~/.cargo/env

Cargo 教程

Cargo 教程

Cargo 是 Rust 的构建系统与包管理器,相当于 npm + webpack。

1. 项目配置(Cargo.toml)

[package]
name = "my_app"          # 包名
version = "0.1.0"        # 版本
edition = "2021"         # Rust 版本
authors = ["You"]

[dependencies]           # 依赖
serde = { version = "1", features = ["derive"] }
tokio = { version = "1", features = ["full"] }

[dev-dependencies]       # 测试依赖
criterion = "0.5"

[profile.release]        # 发布优化
opt-level = 3
lto = true

2. 常用命令

cargo new       # 新建项目(二进制)
cargo new --lib   # 新建库项目
cargo build           # 编译(debug)
cargo build --release # 编译(优化)
cargo run             # 编译并运行
cargo run --release   # 发布模式运行
cargo check           # 快速检查(不生成二进制)
cargo test            # 运行测试
cargo fmt             # 格式化代码
cargo clippy          # 静态检查
cargo doc             # 生成文档
cargo add serde       # 添加依赖(自动改 Cargo.toml)
cargo remove serde    # 移除依赖
cargo tree            # 查看依赖树
cargo update          # 更新依赖版本

3. 添加依赖

# 方式一: 命令行
cargo add serde --features derive
cargo add tokio --features full
cargo add rand --dev        # 开发依赖

# 方式二: 手动编辑 Cargo.toml 后 cargo build

4. 国内镜像配置

# ~/.cargo/config.toml
[source.crates-io]
replace-with = "rsproxy-sparse"

[source.rsproxy-sparse]
registry = "sparse+https://rsproxy.cn/index/"

[registries.rsproxy]
index = "sparse+https://rsproxy.cn/index/"

[net]
git-fetch-with-cli = true

5. workspace(多包项目)

# 根 Cargo.toml
[workspace]
members = ["core", "server", "cli"]
resolver = "2"

# 各子目录有自己的 Cargo.toml
# 在根目录统一构建:
cargo build --workspace

6. 发布 crate

cargo login     # 登录 crates.io
cargo publish          # 发布
cargo publish --dry-run # 预演

Rust 输出到命令行

Rust 输出到命令行

掌握 println! 等宏,是学习 Rust 的第一步。

1. println! 基础

fn main() {
    println!("Hello, world!");        // 带换行
    print!("不换行");                   // 不带换行

    // 格式化占位符
    println!("数字: {}", 42);
    println!("{} + {} = {}", 1, 2, 3);

    // 位置参数
    println!("{1} 和 {0}", "先", "后");   // 后 和 先

    // 命名参数
    println!("{name} 今年 {age} 岁", name = "张三", age = 28);
}

2. 格式化语法

// 宽度与对齐
println!("|{:5}|", 42);        // |   42| 右对齐
println!("|{:<5}|", 42);       // |42   | 左对齐
println!("|{:^5}|", 42);       // | 42  | 居中

// 数字格式
println!("{:b}", 10);          // 1010 二进制
println!("{:o}", 10);          // 12 八进制
println!("{:x}", 255);         // ff 十六进制
println!("{:X}", 255);         // FF 大写
println!("{:.2}", 3.14159);    // 3.14 小数位
println!("{:e}", 1000.0);      // 1e3 科学计数

// 补零
println!("{:04}", 42);         // 0042

// Debug 格式
let v = vec![1, 2, 3];
println!("{:?}", v);           // [1, 2, 3] Debug
println!("{:#?}", v);          // 美化多行 Debug

3. Display vs Debug

// Display: {} 人类可读
// Debug: {:?} 调试输出

#[derive(Debug)]
struct Point { x: i32, y: i32 }

fn main() {
    let p = Point { x: 1, y: 2 };
    println!("{:?}", p);   // Point { x: 1, y: 2 }

    // 需要手动实现 Display 才能用 {}
    // impl std::fmt::Display for Point { ... }
}

4. eprintln! 错误输出

fn main() {
    // stdout: 正常输出
    println!("正常输出");

    // stderr: 错误输出(不混入管道数据)
    eprintln!("错误信息");
}

// 管道测试
// cargo run 2>err.log  # 错误进文件

5. 读取输入

use std::io;

fn main() {
    let mut input = String::new();
    io::stdin()
        .read_line(&mut input)
        .expect("读取失败");

    println!("你输入了: {}", input.trim());
}

Rust 基础语法

Rust 基础语法

Rust 语法融合了 C 的简洁与现代语言的安全特性。

1. 变量与不可变性

fn main() {
    // 默认不可变
    let x = 5;
    // x = 6;  // 错误!x 不可变

    // mut 声明可变
    let mut y = 5;
    y = 6;      // 可以
    println!("y = {}", y);
}

2. 常量与类型标注

const MAX_POINTS: u32 = 100_000;   // 常量(编译期)

fn main() {
    let x: i32 = 5;          // 显式类型
    let f: f64 = 3.14;       // 浮点
    let b: bool = true;      // 布尔
    let c: char = 'A';       // 字符
    let s: &str = "Hello";   // 字符串切片
}

3. 类型推断

let x = 5;              // i32
let f = 3.14;           // f64
let s = "hello";        // &str
let v = vec![1, 2, 3];  // Vec
let t = (1, "a");       // (i32, &str)

4. 遮蔽(Shadowing)

let x = 5;
let x = x + 1;      // 遮蔽,新变量 x = 6
let x = x * 2;      // x = 12
println!("{}", x);  // 12

// 遮蔽可改变类型
let s = "123";
let s = s.len();    // &str → usize

5. 基本数据类型

// 整数
i8 i16 i32 i64 i128   有符号
u8 u16 u32 u64 u128   无符号
usize isize           与指针同宽

// 浮点
f32 f64

// 布尔 / 字符
bool  char(4 字节 Unicode)

// 复合
tuple: (i32, f64, &str)
array: [i32; 5] 固定长度

6. 表达式与语句

// 表达式: 有值(无分号)
let y = {
    let x = 3;
    x + 1       // 表达式,无分号
};              // y = 4

// 语句: 无值(有分号)
let z = 5;      // 语句

// if 也是表达式
let result = if x > 5 { "大" } else { "小" };

7. 注释

// 行注释
/* 块注释 */

/// 文档注释(生成文档)
/// # 示例
/// ```
/// let x = 5;
/// ```
fn example() {}

//! 模块级文档注释

Rust 运算符

Rust 运算符

Rust 提供完整的运算符支持,部分可重载。

1. 算术运算符

let a = 10;
let b = 3;

a + b    // 13
a - b    // 7
a * b    // 30
a / b    // 3(整数除法)
a % b    // 1 取余

// 浮点除法
10.0 / 3.0   // 3.333...
// 注意整数除法会截断

// 溢出行为(debug 模式 panic,release 回绕)
// 需要显式处理用 checked_add 等

2. 复合赋值

let mut x = 10;
x += 5;     // 15
x -= 3;     // 12
x *= 2;     // 24
x /= 4;     // 6
x %= 4;     // 2

3. 比较运算符

==  !=  <  >  <=  >=

let a = 5;
a == 5   // true
a != 3   // true
a < 10   // true
a >= 5   // true

4. 逻辑运算符

&&  与(短路)
||  或(短路)
!   非

let age = 25;
age > 18 && age < 60    // true
age < 18 || age > 60    // false
!(age > 18)             // false

5. 位运算符

let a: u8 = 0b1100;
let b: u8 = 0b1010;

a & b    // 0b1000 与
a | b   // 0b1110 或
a ^ b   // 0b0110 异或
!a      // 取反
a << 1  // 左移 1 位
a >> 1  // 右移 1 位

6. 类型转换

// as 转换
let x: i32 = 5;
let y: f64 = x as f64;      // 5.0
let z: u8 = 255 as u8;      // 255
let c: char = 65 as char;   // 'A'
let n: i32 = 'A' as i32;    // 65

// 需要注意: 大转小会截断
let big: i32 = 300;
let small: u8 = big as u8;  // 44(截断)

// 字符串解析
let n: i32 = "42".parse().unwrap();      // 42
let f: f64 = "3.14".parse().unwrap();    // 3.14
// 或
let n = "42".parse::().unwrap();

7. 运算符重载

use std::ops::Add;

#[derive(Debug, PartialEq)]
struct Point { x: i32, y: i32 }

impl Add for Point {
    type Output = Point;
    fn add(self, other: Point) -> Point {
        Point { x: self.x + other.x, y: self.y + other.y }
    }
}

let p1 = Point { x: 1, y: 2 };
let p2 = Point { x: 3, y: 4 };
println!("{:?}", p1 + p2);   // Point { x: 4, y: 6 }

Rust 数据类型

Rust 数据类型

Rust 是静态强类型语言,类型系统是其安全性的基石。

1. 标量类型

// 整数
let a: i32 = -100;          // 有符号
let b: u64 = 100;           // 无符号
let c: isize = 0;           // 与平台相关

// 浮点
let pi: f32 = 3.14;
let e: f64 = 2.71828;

// 布尔
let t: bool = true;
let f: bool = false;

// 字符(4 字节,Unicode)
let ch: char = '中';
let emoji: char = '😀';

2. 元组(Tuple)

let tup: (i32, f64, char) = (500, 6.4, 'a');

// 解构
let (x, y, z) = tup;
println!("{} {} {}", x, y, z);   // 500 6.4 a

// 索引访问
println!("{}", tup.0);   // 500
println!("{}", tup.2);   // a

// 单元素元组需要逗号
let single = (5,);       // 注意逗号

3. 数组(Array)

// 固定长度
let arr: [i32; 3] = [1, 2, 3];

// 相同值
let zeros = [0; 5];      // [0, 0, 0, 0, 0]

// 访问
println!("{}", arr[0]);  // 1
println!("长度: {}", arr.len());

// 越界会 panic(安全!)
// println!("{}", arr[5]);  // 编译错误/运行时 panic

// 遍历
for x in arr {
    println!("{}", x);
}

4. 切片(Slice)

let arr = [1, 2, 3, 4, 5];
let slice: &[i32] = &arr[1..3];   // [2, 3]
let all: &[i32] = &arr[..];       // 全部
let tail: &[i32] = &arr[2..];     // [3, 4, 5]

// 字符串切片
let s = String::from("hello");
let part = &s[0..2];              // "he"(按字节)

5. 字符串

// &str: 字符串切片(不可变借用)
let s1: &str = "hello";

// String: 可增长字符串
let mut s2 = String::from("hello");
s2.push_str(" world");

// 转换
let s3 = s1.to_string();
let s4 = &s2[..];      // String → &str

// 注意: 不能直接索引 s[0](UTF-8)
// 用 chars() 遍历
for c in s2.chars() {
    println!("{}", c);
}

6. 类型别名与转换

type Age = u8;          // 类型别名
let age: Age = 30;

// 常用转换
let s = 42.to_string();          // "42"
let n: i32 = "42".parse().unwrap();
let f: f64 = 3.14;
let i: i32 = f as i32;           // 3(截断)

Rust 注释

Rust 注释

Rust 的注释体系完善,支持行注释、文档注释与代码示例测试。

1. 基本注释

// 行注释
// Rust 中 // 是标准注释方式

/* 块注释 */
/* 可以
   多行 */

fn main() {
    // 代码中的注释
    let x = 5;  // 行尾注释
}

2. 文档注释(///)

/// 计算两数之和
///
/// # 参数
/// - `a`: 第一个数
/// - `b`: 第二个数
///
/// # 返回
/// a + b 的结果
///
/// # 示例
/// ```
/// let result = add(2, 3);
/// assert_eq!(result, 5);
/// ```
pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

3. 模块文档(//!)

//! 这是模块级文档注释
//! 描述整个模块的用途与用法
//! 放在文件或模块开头

/// 函数级文档
pub fn foo() {}

// 生成文档: cargo doc --open

4. 文档测试

/// ```
/// let x = 5;
/// assert!(x > 0);
/// ```
pub fn documented() {}

// cargo test 会运行文档中的代码块!
// 文档中的示例可以当测试用

// 忽略测试的示例
/// ```ignore
/// 不会执行的代码
/// ```

/// ```no_run
/// 编译但不运行
/// ```

5. 常见注释标记

// TODO: 待完成的功能
// FIXME: 需要修复的问题
// HACK: 临时方案,需要改进
// NOTE: 注意事项

// 配合 IDE 显示待办列表

6. 注释最佳实践

1. 公共 API 写文档注释(生成文档)
2. 解释"为什么"而非"是什么"
3. 复杂算法注明思路
4. 注释要随代码更新
5. 使用 markdown 格式增强可读性

Rust 函数

Rust 函数

函数是 Rust 代码组织的基本单元,支持模式匹配参数、泛型与闭包。

1. 定义与调用

fn main() {
    greet("张三");
    let sum = add(3, 5);
    println!("sum = {}", sum);
}

// 无返回值
fn greet(name: &str) {
    println!("你好, {}", name);
}

// 有返回值(-> 类型)
fn add(a: i32, b: i32) -> i32 {
    a + b        // 表达式作为返回值(无分号)
}

2. 返回值规则

fn f1() -> i32 {
    return 42;    // 显式 return(早退用)
}

fn f2() -> i32 {
    42            // 隐式返回(最后一个表达式)
}

fn f3() -> i32 {
    42;           // 错误!有分号是语句,返回 ()
}

// 无返回值
fn f4() {}        // 返回 () 单元类型

3. 多个返回值(元组)

fn min_max(nums: &[i32]) -> (i32, i32) {
    let mut min = nums[0];
    let mut max = nums[0];
    for &n in nums {
        if n < min { min = n; }
        if n > max { max = n; }
    }
    (min, max)
}

fn main() {
    let (min, max) = min_max(&[3, 1, 4, 1, 5]);
    println!("min={} max={}", min, max);   // min=1 max=5
}

4. 泛型函数

// T 可以是任意类型
fn largest(list: &[T]) -> &T {
    let mut largest = &list[0];
    for item in list {
        if item > largest {
            largest = item;
        }
    }
    largest
}

fn main() {
    let nums = vec![1, 5, 3, 9, 2];
    println!("{}", largest(&nums));     // 9

    let chars = vec!['a', 'z', 'm'];
    println!("{}", largest(&chars));    // z
}

5. 高阶函数(函数指针)

fn apply_twice(f: fn(i32) -> i32, x: i32) -> i32 {
    f(f(x))
}

fn double(x: i32) -> i32 { x * 2 }

fn main() {
    let result = apply_twice(double, 5);
    println!("{}", result);   // 20
}

6. 闭包(匿名函数)

fn main() {
    // 闭包: || 语法
    let add = |a: i32, b: i32| a + b;
    println!("{}", add(1, 2));    // 3

    // 捕获外部变量
    let factor = 10;
    let multiply = |x| x * factor;   // 捕获 factor
    println!("{}", multiply(5));     // 50

    // 高阶用法
    let nums = vec![1, 2, 3, 4];
    let doubled: Vec = nums.iter().map(|x| x * 2).collect();
    let evens: Vec = nums.iter().filter(|x| **x % 2 == 0).collect();
}

Rust 条件语句

Rust 条件语句

Rust 的 if 是表达式(有值),支持多种条件结构。

1. if / else if / else

fn main() {
    let score = 85;

    if score >= 90 {
        println!("优秀");
    } else if score >= 60 {
        println!("及格");
    } else {
        println!("不及格");
    }
}

2. if 作为表达式

let number = 7;
let result = if number % 2 == 0 { "偶数" } else { "奇数" };
println!("{}", result);   // 奇数

// 类型必须一致
let x = if true { 10 } else { 20 };
// let y = if true { 10 } else { "str" };  // 错误!类型不同

3. 循环中的条件

// while 循环
let mut count = 0;
while count < 5 {
    println!("count = {}", count);
    count += 1;
}

// loop 无限循环(用 break 退出)
let mut i = 0;
loop {
    i += 1;
    if i > 3 { break; }
    println!("i = {}", i);
}

// loop 可返回值
let mut j = 0;
let result = loop {
    j += 1;
    if j == 5 {
        break j * 2;    // 返回 10
    }
};
println!("result = {}", result);   // 10

4. for 循环

// 范围
for i in 1..5 {          // 1,2,3,4
    println!("{}", i);
}
for i in 1..=5 {         // 1,2,3,4,5(含结尾)
    println!("{}", i);
}

// 数组/向量
let arr = [10, 20, 30];
for v in arr {
    println!("{}", v);
}

// 带索引
for (i, v) in arr.iter().enumerate() {
    println!("arr[{}] = {}", i, v);
}

// 反向
for i in (1..=5).rev() {
    println!("{}", i);   // 5 4 3 2 1
}

5. break / continue / 标签

// break: 退出循环
// continue: 跳过本次

// 循环标签(嵌套循环跳出外层)
'outer: for i in 1..=3 {
    for j in 1..=3 {
        if j == 2 { break 'outer; }
        println!("({}, {})", i, j);   // 只输出 (1, 1)
    }
}

6. match 匹配(最强条件)

let number = 13;

match number {
    1 => println!("一"),
    2 | 3 | 5 | 7 => println!("质数"),
    10..=20 => println!("10 到 20 之间"),   // 范围
    _ => println!("其他"),                   // 兜底
}

// match 是表达式,可赋值
let grade = match score {
    90..=100 => "A",
    80..=89 => "B",
    70..=79 => "C",
    60..=69 => "D",
    _ => "F",
};

Rust 循环

Rust 循环

Rust 提供 loop、while、for 三种循环,各有适用场景。

1. loop(无限循环)

// loop 会一直执行,直到 break
let mut counter = 0;

let result = loop {
    counter += 1;
    if counter == 10 {
        break counter * 2;    // break 可带值
    }
};
println!("result = {}", result);   // 20

// 服务器/监听器常见模式
loop {
    // 处理请求...
    // 检查退出条件
    if should_exit { break; }
}

2. while(条件循环)

let mut number = 3;
while number != 0 {
    println!("{}!", number);
    number -= 1;
}
println!("发射!");

// while let(模式匹配循环)
let mut stack = vec![1, 2, 3];
while let Some(top) = stack.pop() {
    println!("{}", top);    // 3 2 1
}

3. for(集合遍历)

// for 是最常用的循环
let names = ["Alice", "Bob", "Carol"];

for name in names {
    println!("{}", name);
}

// 范围
for n in 1..=100 {
    // 求 1..100 之和
}

// 对迭代器
let numbers = vec![5, 3, 8, 1];
for n in numbers.iter() {
    println!("{}", n);
}
// 注意: numbers 仍可用(借用)
// for n in numbers 则所有权移动

4. 循环中的控制流

// break: 退出
// continue: 跳过本次

for i in 1..=10 {
    if i % 2 == 0 {
        continue;       // 跳过偶数
    }
    if i > 7 {
        break;          // 大于 7 退出
    }
    println!("{}", i);  // 1 3 5 7
}

5. 循环标签与嵌套

'outer: for i in 1..=5 {
    println!("外层: {}", i);
    'inner: for j in 1..=5 {
        if j == 3 {
            continue 'outer;    // 跳到外层下一次
        }
        if i * j > 10 {
            break 'outer;       // 退出外层
        }
        println!("  内层: {}", j);
    }
}

6. 迭代器方法(推荐风格)

// Rust 风格: 多用迭代器方法替代手写循环
let nums = vec![1, 2, 3, 4, 5];

// map: 转换
let doubled: Vec<_> = nums.iter().map(|x| x * 2).collect();

// filter: 过滤
let evens: Vec<_> = nums.iter().filter(|x| **x % 2 == 0).collect();

// sum / product
let sum: i32 = nums.iter().sum();

// fold: 聚合
let total: i32 = nums.iter().fold(0, |acc, x| acc + x);

// chain: 链式
let result: Vec<_> = nums.iter()
    .filter(|x| **x > 2)
    .map(|x| x * 10)
    .collect();     // [30, 40, 50]

Rust 迭代器

Rust 迭代器

迭代器是 Rust 集合处理的核心抽象,配合闭包可以写出简洁高效的数据处理代码。

1. 什么是迭代器

// 迭代器惰性: 只在调用消费方法时才执行
let nums = vec![1, 2, 3, 4, 5];
let iter = nums.iter();   // 创建迭代器,尚未执行

// 消费: for 循环
for n in iter {
    println!("{}", n);
}

2. 三种 iter

let v = vec![1, 2, 3];

v.iter()        // &T 借用迭代(&1, &2, &3)
v.iter_mut()    // &mut T 可变借用
v.into_iter()   // T 所有权(移动)

// 数组
let arr = [1, 2, 3];
arr.iter().for_each(|x| println!("{}", x));

3. 常用适配器(转换)

let nums = vec![1, 2, 3, 4, 5, 6];

// map: 变换
let squares: Vec = nums.iter().map(|x| x * x).collect();
// [1, 4, 9, 16, 25, 36]

// filter: 过滤
let evens: Vec<&i32> = nums.iter().filter(|x| **x % 2 == 0).collect();
// [2, 4, 6]

// take / skip
let first3: Vec<&i32> = nums.iter().take(3).collect();     // [1,2,3]
let after2: Vec<&i32> = nums.iter().skip(2).collect();     // [3,4,5,6]

// enumerate: 带索引
for (i, x) in nums.iter().enumerate() {
    println!("nums[{}] = {}", i, x);
}

// zip: 配对
let a = [1, 2, 3];
let b = ["a", "b", "c"];
for (x, y) in a.iter().zip(b.iter()) {
    println!("{} -> {}", x, y);
}

4. 消费方法

let nums = vec![1, 2, 3, 4, 5];

let count = nums.iter().count();            // 5
let sum: i32 = nums.iter().sum();           // 15
let product: i32 = nums.iter().product();   // 120

let max = nums.iter().max();                // Some(&5)
let min = nums.iter().min();                // Some(&1)

let any = nums.iter().any(|x| x > 4);       // true
let all = nums.iter().all(|x| x > 0);       // true

// find / position
let found = nums.iter().find(|x| **x == 3);     // Some(&3)
let pos = nums.iter().position(|x| *x == 3);    // Some(2)

// fold: 通用聚合
let total = nums.iter().fold(0, |acc, x| acc + x);   // 15

// collect: 收集到容器
let doubled: Vec = nums.iter().map(|x| x * 2).collect();
let filtered: Vec = nums.into_iter().filter(|x| x % 2 == 0).collect();

5. 链式组合示例

let nums = vec![1, 2, 3, 4, 5, 6, 7, 8];

// 过滤偶数 → 平方 → 取前 3 → 求和
let result: i32 = nums.iter()
    .filter(|x| **x % 2 == 0)       // [2,4,6,8]
    .map(|x| x * x)                 // [4,16,36,64]
    .take(3)                        // [4,16,36]
    .sum();                         // 56
println!("{}", result);   // 56

6. 自定义迭代器

// 实现 Iterator trait
struct Counter {
    count: u32,
}

impl Counter {
    fn new() -> Counter {
        Counter { count: 0 }
    }
}

impl Iterator for Counter {
    type Item = u32;
    fn next(&mut self) -> Option {
        self.count += 1;
        if self.count < 6 {
            Some(self.count)
        } else {
            None
        }
    }
}

fn main() {
    let sum: u32 = Counter::new()
        .map(|x| x * 2)
        .sum();
    println!("{}", sum);   // 30
}

Rust 闭包

Rust 闭包(Closure)

闭包是能捕获环境变量的匿名函数,Rust 中通过所有权规则严格管理闭包的捕获方式。

1. 闭包语法

// 完整形式
let add = |a: i32, b: i32| -> i32 { a + b };

// 类型可推断
let add = |a, b| a + b;
println!("{}", add(1, 2));   // 3

// 无参数
let hello = || println!("Hello!");
hello();

// 闭包调用与函数类似
let square = |x: i32| x * x;
println!("{}", square(5));   // 25

2. 捕获环境变量

let factor = 3;
let multiply = |x| x * factor;   // 捕获 factor
println!("{}", multiply(10));    // 30

// 捕获方式由编译器自动选择:
// FnOnce: 按值捕获(消耗所有权)
// FnMut: 可变借用(可修改)
// Fn: 不可变借用(只读)

let mut count = 0;
let mut increment = || {
    count += 1;       // 可变借用 → FnMut
};
increment();
increment();
println!("count = {}", count);   // 2

3. move 关键字

// move 强制按值捕获(所有权转移)
let s = String::from("hello");

let closure = move || {
    println!("{}", s);   // s 的所有权被移动进闭包
};
closure();
// println!("{}", s);    // 错误!s 已被移动

// 常用于线程
use std::thread;
let data = String::from("thread data");
thread::spawn(move || {
    println!("{}", data);
}).join().unwrap();

4. 作为参数

// 泛型闭包参数
fn apply(f: F, x: i32) -> i32
where
    F: Fn(i32) -> i32,       // 约束: 闭包类型
{
    f(x)
}

// Fn / FnMut / FnOnce 三种 trait
fn apply_once(f: F) {
    f();
}

fn apply_mut(mut f: F) {
    f();
}

fn apply_fn(f: F) {
    f();
}

5. 返回闭包

// 返回闭包: 用 impl Fn 或 Box
fn make_multiplier(factor: i32) -> impl Fn(i32) -> i32 {
    move |x| x * factor    // move 捕获 factor
}

fn main() {
    let times3 = make_multiplier(3);
    println!("{}", times3(10));   // 30
}

// 不同闭包类型需用 Box
fn make_adder(add: i32) -> Box i32> {
    Box::new(move |x| x + add)
}

6. 与迭代器配合(经典用法)

let nums = vec![1, 2, 3, 4, 5];

let result: Vec = nums.iter()
    .map(|x| x * x)                 // 闭包
    .filter(|x| x % 2 == 0)         // 闭包
    .collect();
println!("{:?}", result);   // [4, 16]

// 排序闭包
let mut scores = vec![85, 92, 78, 90];
scores.sort_by(|a, b| b.cmp(a));    // 降序
println!("{:?}", scores);   // [92, 90, 85, 78]

Rust 所有权

Rust 所有权(Ownership)

所有权是 Rust 最核心的概念,它让内存安全无需垃圾回收即可实现。

1. 所有权规则

1. 每个值都有一个所有者(owner)
2. 同一时刻只有一个所有者
3. 所有者离开作用域,值被自动释放(drop)
{
    let s = String::from("hello");   // s 拥有字符串
    // 使用 s
}   // 作用域结束,s 被释放,内存自动回收
// s 在这里不可用

2. 移动(Move)

let s1 = String::from("hello");
let s2 = s1;     // 所有权从 s1 移动到 s2(浅拷贝+失效)

// println!("{}", s1);   // 错误!s1 已失效
println!("{}", s2);      // hello

// 不是拷贝!字符串数据只存在一份,所有权转移
// 避免双重释放(与 C++ move 语义类似)

3. 克隆(Clone)

let s1 = String::from("hello");
let s2 = s1.clone();    // 深拷贝,两份数据
println!("{} {}", s1, s2);   // hello hello

// 拷贝(Copy)类型: 小数据类型直接复制
// i32/f64/bool/char/元组(内部都是 Copy)
let x = 5;
let y = x;      // Copy,不需要 clone
println!("{} {}", x, y);   // 5 5

4. 函数参数的所有权

fn takes_ownership(s: String) {
    println!("{}", s);
}   // s 在这里被释放

fn makes_copy(x: i32) {
    println!("{}", x);
}

fn main() {
    let s = String::from("hello");
    takes_ownership(s);    // 所有权移入函数
    // println!("{}", s);  // 错误!s 已移动

    let n = 5;
    makes_copy(n);         // Copy 类型,仍可用
    println!("{}", n);     // 5
}

5. 返回值转移所有权

fn gives_back() -> String {
    String::from("返回值")
}

fn takes_and_gives(s: String) -> String {
    s    // 返回,所有权转移回去
}

fn main() {
    let s1 = gives_back();
    let s2 = takes_and_gives(s1);
    println!("{}", s2);
    // s1 已移动到函数又移回来,此处 s1 失效
}

6. 引用与借用(解决移动问题)

fn calculate_len(s: &String) -> usize {   // & 借用
    s.len()
}   // s 是借用,不释放

fn main() {
    let s = String::from("hello");
    let len = calculate_len(&s);   // 传引用
    println!("{} 长度 {}", s, len);   // s 仍可用
}

// 规则:
// 1. 任意时刻要么一个可变引用,要么多个不可变引用
// 2. 引用必须始终有效(不悬垂)

let mut s = String::from("hello");
let r1 = &s;           // 不可变借用
// let r2 = &mut s;    // 错误!已有不可变借用
println!("{}", r1);

7. 引用的规则

let mut s = String::from("hello");

// 多个不可变借用: OK
let r1 = &s;
let r2 = &s;
println!("{} {}", r1, r2);

// 可变借用: 同一时刻只能一个
let r3 = &mut s;
r3.push_str(" world");

// 借用结束后才能再借用
println!("{}", s);   // hello world

// 悬垂引用: 编译器拒绝
// fn dangle() -> &String {
//     let s = String::from("hello");
//     &s    // 错误!s 离开作用域被释放
// }

Rust Slice(切片)类型

Rust Slice(切片)类型

切片(Slice)是对集合连续部分的不拥有所有权的引用,安全且高效。

1. 什么是切片

// 切片 = 指向集合某段的引用
// 类型: &[T](数组切片)、&str(字符串切片)

let arr = [1, 2, 3, 4, 5];
let slice: &[i32] = &arr[1..4];    // [2, 3, 4]
// 不拥有 arr,只是借用其中一段

2. 字符串切片

let s = String::from("hello world");

let hello = &s[0..5];      // "hello"
let world = &s[6..11];     // "world"
let whole = &s[..];        // "hello world"

// 切片必须是 UTF-8 边界
// let bad = &s[0..4];  // 若边界在汉字中间会 panic

// 字符串字面量本身是切片
let lit: &str = "hello";   // &str 类型

3. 切片语法

let arr = [1, 2, 3, 4, 5];

&arr[..]      // 全部 [1,2,3,4,5]
&arr[1..]     // [2,3,4,5]
&arr[..3]     // [1,2,3]
&arr[1..3]    // [2,3]
&arr[1..=3]   // [2,3,4] 含结尾

// 空切片
&arr[2..2]    // []

4. 切片 vs 数组 vs String

// 数组: 拥有数据,固定长度
let arr: [i32; 5] = [1, 2, 3, 4, 5];

// 切片: 借用数据,不拥有
let slice: &[i32] = &arr[1..3];

// String: 拥有,可增长
let mut s = String::from("hello");
s.push('!');

// &str: 借用字符串,不可变
let s2: &str = &s;

// 参数设计: 能用 &str 就用 &str(更通用)
fn print_str(s: &str) {
    println!("{}", s);
}
// 可以传 &String 和 &str

5. 函数中使用切片

fn sum(slice: &[i32]) -> i32 {
    slice.iter().sum()
}

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 nums = [1, 2, 3, 4, 5];
    println!("{}", sum(&nums[1..4]));   // 9

    let s = String::from("hello world");
    println!("{}", first_word(&s));     // hello
}

6. 可变切片

let mut arr = [1, 2, 3, 4, 5];
let slice = &mut arr[1..4];    // 可变切片
slice[0] = 99;
println!("{:?}", arr);         // [1, 99, 3, 4, 5]

7. 切片的安全保证

// 越界在编译/运行时检查
// 借用规则保证: 切片存在时,原集合不可变/不可整体移动
let mut v = vec![1, 2, 3];
let slice = &v[..2];
// v.push(4);   // 错误!切片借用中,不能修改 v
println!("{:?}", slice);

Rust 结构体

Rust 结构体(Struct)

结构体是 Rust 自定义数据类型的主要方式,用于组织相关联的数据。

1. 定义与实例化

struct User {
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}

fn main() {
    let user = User {
        email: String::from("a@example.com"),
        username: String::from("zhangsan"),
        active: true,
        sign_in_count: 1,
    };
    println!("{}", user.username);
}

2. 可变实例与更新

let mut user = User {
    email: String::from("a@example.com"),
    username: String::from("zhangsan"),
    active: true,
    sign_in_count: 1,
};
user.email = String::from("b@example.com");

// 结构体更新语法(..user)
let user2 = User {
    email: String::from("c@example.com"),
    ..user      // 其余字段从 user 复制
};
// 注意: user 的 String 字段被移动后 user 不可用

3. 构造函数模式

struct User {
    username: String,
    email: String,
    active: bool,
}

impl User {
    fn new(username: String, email: String) -> User {
        User {
            username,
            email,
            active: true,
        }
    }
}

let u = User::new(
    String::from("zhang"),
    String::from("z@example.com")
);

4. 元组结构体(Tuple Struct)

struct Color(i32, i32, i32);
struct Point(i32, i32, i32);

let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);

// 访问
println!("{}", black.0);   // 0

// 解构
let Color(r, g, b) = black;
println!("{} {} {}", r, g, b);

5. 单元结构体(Unit Struct)

// 无字段,用于标记/实现 trait
struct Marker;

impl Marker {
    fn new() -> Marker {
        Marker
    }
}

let m = Marker;
let m2 = Marker::new();

6. 方法(Methods)

struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    // 方法: &self 借用
    fn area(&self) -> u32 {
        self.width * self.height
    }

    // 可变方法: &mut self
    fn scale(&mut self, factor: u32) {
        self.width *= factor;
        self.height *= factor;
    }

    // 关联函数(无 self): 类似静态方法
    fn square(size: u32) -> Rectangle {
        Rectangle { width: size, height: size }
    }
}

fn main() {
    let mut rect = Rectangle { width: 3, height: 4 };
    println!("面积: {}", rect.area());   // 12
    rect.scale(2);
    println!("面积: {}", rect.area());   // 48

    let sq = Rectangle::square(5);
    println!("{}", sq.area());           // 25
}

7. 派生 Trait

#[derive(Debug, Clone, PartialEq)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p1 = Point { x: 1, y: 2 };
    let p2 = p1.clone();
    println!("{:?}", p1);            // Debug 输出
    println!("{}", p1 == p2);        // PartialEq -> true
}

Rust 枚举类

Rust 枚举类(Enum)

Rust 枚举比 C 语言强大得多,可以携带数据,是表达"可能性"的首选。

1. 基本枚举

enum Direction {
    North,
    South,
    East,
    West,
}

fn move_to(dir: Direction) {
    match dir {
        Direction::North => println!("向北"),
        Direction::South => println!("向南"),
        Direction::East => println!("向东"),
        Direction::West => println!("向西"),
    }
}

fn main() {
    let d = Direction::North;
    move_to(d);
}

2. 携带数据(关联值)

enum Message {
    Quit,                          // 无数据
    Move { x: i32, y: i32 },       // 命名数据
    Write(String),                 // 单个数据
    ChangeColor(u8, u8, u8),       // 元组数据
}

fn process(msg: Message) {
    match msg {
        Message::Quit => println!("退出"),
        Message::Move { x, y } => {
            println!("移动到 ({}, {})", x, y);
        }
        Message::Write(text) => println!("写入: {}", text),
        Message::ChangeColor(r, g, b) => {
            println!("颜色: {} {} {}", r, g, b);
        }
    }
}

3. Option 枚举(核心)

// Option: 有值(Some)或无值(None)
// 消除空指针问题
let some_number = Some(5);
let some_string = Some("hello");
let none: Option = None;

// 必须处理 None,不能直接当数值用
fn double(x: Option) -> i32 {
    match x {
        Some(n) => n * 2,
        None => 0,
    }
}

// 常用方法
let x = Some(10);
println!("{}", x.unwrap_or(0));      // 10
println!("{}", x.unwrap_or_default()); // 10
if let Some(v) = x {
    println!("值是 {}", v);
}
let y: Option = None;
println!("{}", y.unwrap_or(42));     // 42

4. match 的穷尽性

// match 必须覆盖所有情况(穷尽性检查)
let x = Some(5);
match x {
    Some(n) => println!("{}", n),
    None => println!("无值"),
    // 如果漏掉 None,编译错误!
}

// _ 通配符处理剩余情况
let n = 3;
match n {
    1 => println!("一"),
    2 => println!("二"),
    _ => println!("其他"),    // 兜底
}

5. if let 简写

// 只关心一种情况的简写
let config_max = Some(3u8);

match config_max {
    Some(max) => println!("最大值 {}", max),
    _ => (),
}
// 等价写法
if let Some(max) = config_max {
    println!("最大值 {}", max);
}

// while let
let mut stack = vec![1, 2, 3];
while let Some(top) = stack.pop() {
    println!("{}", top);
}

6. 方法(match self)

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter,
}

impl Coin {
    fn value_in_cents(&self) -> u32 {
        match self {
            Coin::Penny => 1,
            Coin::Nickel => 5,
            Coin::Dime => 10,
            Coin::Quarter => 25,
        }
    }
}

fn main() {
    let coin = Coin::Quarter;
    println!("{} 分", coin.value_in_cents());   // 25
}

7. 递归枚举

// 链表等递归结构需 Box 包装(间接引用)
enum List {
    Cons(i32, Box),
    Nil,
}

fn main() {
    let list = List::Cons(
        1, Box::new(List::Cons(2, Box::new(List::Nil))));
    println!("递归枚举(链表)创建成功");
}

Rust 组织管理

Rust 组织管理(模块系统)

Rust 用模块(module)、包(package)、crate 组织代码,实现清晰的代码结构。

1. 基本概念

Package(包):  Cargo 管理的项目(一个 Cargo.toml)
Crate(箱子):  编译单元(二进制或库)
Module(模块): 组织代码的命名空间

cargo new myapp
# ├── src/main.rs    二进制 crate
# └── Cargo.toml

cargo new --lib mylib
# ├── src/lib.rs     库 crate
# └── Cargo.toml

2. 模块定义

// src/main.rs
mod math {                    // 定义模块
    pub fn add(a: i32, b: i32) -> i32 {  // pub 公开
        a + b
    }

    fn secret() {             // 私有(默认)
        println!("内部函数");
    }

    pub mod utils {           // 嵌套模块
        pub fn double(x: i32) -> i32 {
            x * 2
        }
    }
}

fn main() {
    println!("{}", math::add(1, 2));      // 3
    println!("{}", math::utils::double(4));  // 8
    // math::secret();   // 错误!私有
}

3. 文件模块

// src/main.rs
mod math;         // 从 math.rs 加载模块

// src/math.rs
pub fn add(a: i32, b: i32) -> i32 { a + b }

// 或目录方式
// src/math/mod.rs(旧风格)
// src/math/utils.rs

// 目录 + 文件(推荐)
// src/math/mod.rs 或 src/math.rs
// ├── math.rs
// └── math/
//     └── utils.rs  → mod utils;

// 现代风格(2021 edition):
// src/math.rs  +  src/math/utils.rs

4. use 引入

mod math;

// 引入
use math::add;
use math::utils::double;
use std::collections::HashMap;

// 相对/绝对路径
use crate::math::add;        // 绝对(crate 根)
use self::math::add;         // 相对(self)

// 别名
use math::add as sum;

// 通配
use math::*;

fn main() {
    println!("{}", add(1, 2));
    let mut map = HashMap::new();
    map.insert("k", 1);
}

5. pub use 再导出

// 库的入口统一导出
// src/lib.rs
mod internal;

pub use internal::PublicStruct;   // 再导出

// 使用方
// use mylib::PublicStruct;   // 不用知道内部路径

6. 可见性

pub          公开(所有模块可见)
pub(crate)   crate 内部可见
pub(super)   父模块可见
pub(in path) 指定路径可见
(默认)       当前模块及子模块可见

pub struct User {
    pub name: String,     // 字段公开
    age: u8,              // 字段私有
}

7. 依赖外部 crate

// Cargo.toml
[dependencies]
serde = { version = "1", features = ["derive"] }
rand = "0.8"

// main.rs
use rand::Rng;

fn main() {
    let n: u32 = rand::thread_rng().gen_range(1..=100);
    println!("{}", n);
}

Rust 错误处理

Rust 错误处理

Rust 没有异常机制,使用 Result 与 Option 显式处理错误,让错误处理强制、清晰、安全。

1. Result 枚举

// Result: Ok(T) 成功 / Err(E) 失败
enum Result {
    Ok(T),
    Err(E),
}

use std::fs::File;

fn main() {
    let f = File::open("hello.txt");

    let f = match f {
        Ok(file) => file,
        Err(error) => panic!("打开失败: {:?}", error),
    };
}

2. 常用错误处理方式

// 1. expect: 失败直接 panic
let f = File::open("a.txt").expect("文件不存在");

// 2. unwrap: 失败 panic(简洁但鲁莽)
let f = File::open("a.txt").unwrap();

// 3. 处理错误
let f = match File::open("a.txt") {
    Ok(file) => file,
    Err(e) => {
        eprintln!("错误: {}", e);
        return;    // 或返回 Err
    }
};

3. ? 运算符(推荐)

// ? 遇到 Err 自动返回,函数必须返回 Result
use std::fs::File;
use std::io::{self, Read};

fn read_username() -> Result {
    let mut f = File::open("user.txt")?;   // Err 直接返回
    let mut s = String::new();
    f.read_to_string(&mut s)?;
    Ok(s)
}

fn main() -> Result<(), io::Error> {
    let name = read_username()?;
    println!("用户: {}", name);
    Ok(())
}

// ? 可自动转换错误类型(From trait)
fn read_file() -> Result> {
    let content = std::fs::read_to_string("a.txt")?;
    let n: i32 = content.trim().parse()?;    // 错误自动转换
    Ok(format!("{}", n))
}

4. 自定义错误类型

use std::fmt;

#[derive(Debug)]
enum MyError {
    NotFound(String),
    InvalidInput(String),
    Io(std::io::Error),
}

impl fmt::Display for MyError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            MyError::NotFound(s) => write!(f, "未找到: {}", s),
            MyError::InvalidInput(s) => write!(f, "无效输入: {}", s),
            MyError::Io(e) => write!(f, "IO 错误: {}", e),
        }
    }
}

impl std::error::Error for MyError {}

// 错误转换
impl From for MyError {
    fn from(e: std::io::Error) -> Self {
        MyError::Io(e)
    }
}

fn read_config() -> Result {
    let content = std::fs::read_to_string("config.toml")?;  // 自动转换
    Ok(content)
}

5. 优雅错误处理库

// anyhow: 应用层,任意错误
// thiserror: 库层,自定义错误

// Cargo.toml
// anyhow = "1"
use anyhow::{Context, Result};

fn main() -> Result<()> {
    let content = std::fs::read_to_string("config.toml")
        .context("读取配置文件失败")?;   // 添加上下文
    println!("{}", content);
    Ok(())
}

// thiserror 示例
use thiserror::Error;

#[derive(Error, Debug)]
enum AppError {
    #[error("用户 {0} 不存在")]
    UserNotFound(String),
    #[error("网络错误")]
    Network,
}

6. 错误处理最佳实践

1. 库代码: 返回自定义错误类型(Result)
2. 应用代码: anyhow 简化处理
3. 简单脚本: unwrap/expect(快速原型)
4. 用户输入错误: 正常处理,不 panic
5. panic 留给: 不可恢复的错误(数组越界等)
6. 用 context 增加错误上下文信息

Rust 泛型与特性

Rust 泛型与特性(Trait)

泛型让代码适用于多种类型,trait 定义共享行为,两者结合构成 Rust 抽象的基础。

1. 泛型函数

// 返回两个数中较大者
fn max(a: T, b: T) -> T {
    if a > b { a } else { b }
}

fn main() {
    println!("{}", max(1, 2));            // i32
    println!("{}", max(1.5, 0.5));        // f64
    println!("{}", max('a', 'z'));        // char
}

// 泛型结构体
struct Point {
    x: T,
    y: T,
}

// 泛型枚举
enum Result {
    Ok(T),
    Err(E),
}

2. Trait 定义

// trait 定义共享行为(类似接口)
trait Summary {
    fn summarize(&self) -> String;

    // 带默认实现的方法
    fn author(&self) -> String {
        String::from("未知作者")
    }
}

struct Article {
    title: String,
    author: String,
}

impl Summary for Article {
    fn summarize(&self) -> String {
        format!("《{}》by {}", self.title, self.author)
    }
}

fn main() {
    let article = Article {
        title: String::from("Rust 教程"),
        author: String::from("张三"),
    };
    println!("{}", article.summarize());
    println!("{}", article.author());   // 默认实现
}

3. Trait 作为参数

// 1. impl Trait 语法
fn notify(item: &impl Summary) {
    println!("通知: {}", item.summarize());
}

// 2. 泛型约束(Trait Bound)
fn notify2(item: &T) {
    println!("通知: {}", item.summarize());
}

// 3. 多个约束
fn notify3(item: &T) {}

// 4. where 子句(清晰)
fn notify4(a: &T, b: &U)
where
    T: Summary + Clone,
    U: Summary + Debug,
{}

// 5. 返回 trait
fn returns_summarizable() -> impl Summary {
    Article { title: String::from("R"), author: String::from("B") }
}

4. 常用标准 trait

Clone      复制(深拷贝)   #[derive(Clone)]
Copy       位拷贝          #[derive(Copy, Clone)]
Debug      调试输出 {:?}   #[derive(Debug)]
PartialEq  相等比较        #[derive(PartialEq)]
Eq         全等
PartialOrd 比较
Ord        全序
Display    显示输出 {}
Iterator   迭代器
Into/From  类型转换
Default    默认值

// 示例
#[derive(Debug, Clone, PartialEq)]
struct User {
    name: String,
    age: u8,
}

5. 常用泛型组合

// Option 与 Result
fn safe_divide(a: f64, b: f64) -> Result {
    if b == 0.0 {
        Err(String::from("不能除以零"))
    } else {
        Ok(a / b)
    }
}

fn main() {
    let r = safe_divide(10.0, 2.0);
    match r {
        Ok(v) => println!("结果 {}", v),
        Err(e) => println!("错误 {}", e),
    }
}

// Vec、HashMap 等标准容器都是泛型

6. Trait 对象

// 动态分发: 运行时决定具体类型
// 需要 Box
trait Draw {
    fn draw(&self);
}

struct Circle;
impl Draw for Circle {
    fn draw(&self) { println!("画圆"); }
}
struct Square;
impl Draw for Square {
    fn draw(&self) { println!("画方"); }
}

fn main() {
    let shapes: Vec> = vec![
        Box::new(Circle),
        Box::new(Square),
    ];
    for s in shapes {
        s.draw();
    }
}

// 静态分发(泛型) vs 动态分发(dyn)
// 泛型: 编译期展开,快,但代码膨胀
// dyn: 运行时查找,灵活,小开销

Rust 生命周期

Rust 生命周期(Lifetime)

生命周期是引用有效范围的标注,是 Rust 防止悬垂引用的机制。

1. 为什么需要生命周期

// 引用必须始终有效,否则悬垂
fn main() {
    let r;
    {
        let x = 5;
        r = &x;      // 错误!x 在作用域结束后被释放
    }
    println!("{}", r);
}

// 编译器通过生命周期检查引用有效性

2. 生命周期标注语法

// 语法: &'a T(生命周期 'a 的引用)
// 泛型生命周期参数

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");
    let s2 = String::from("short");
    let result = longest(&s1, &s2);
    // 返回值生命周期取两者较短者
    println!("{}", result);
}

3. 生命周期省略规则

// 编译器自动推断,不必显式写
// 规则:
// 1. 每个输入引用分配生命周期
// 2. 只有一个输入生命周期 → 输出用它
// 3. 多个输入,其中一个是 &self → 输出用 self 的

// 不需要标注(单参数)
fn first_word(s: &str) -> &str {
    &s[..]
}

// 需要标注(多参数,输出与输入关联)
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() { x } else { y }
}

4. 结构体中的生命周期

// 结构体持有引用时需要标注
struct Excerpt<'a> {
    part: &'a str,    // 引用必须标注生命周期
}

impl<'a> Excerpt<'a> {
    fn level(&self) -> i32 { 3 }
}

fn main() {
    let novel = String::from("第一章 内容...");
    let first = novel.split('.').next().unwrap();
    let excerpt = Excerpt { part: first };
    println!("{}", excerpt.part);
}

5. 生命周期与泛型、trait 结合

fn longest_with_announcement<'a, T>(
    x: &'a str,
    y: &'a str,
    ann: T,
) -> &'a str
where
    T: std::fmt::Display,
{
    println!("公告: {}", ann);
    if x.len() > y.len() { x } else { y }
}

6. 静态生命周期 'static

// 'static: 整个程序运行期间有效
// 字符串字面量就是 'static

let s: &'static str = "hello";   // 字面量是 'static

// 动态字符串转 'static(内存泄漏,慎用)
let leak: &'static str = Box::leak(
    String::from("leak").into_boxed_str());

// 常配合 trait 对象
fn get_display() -> Box {
    Box::new(String::from("hello"))
}

7. 生命周期最佳实践

1. 大多数情况编译器自动处理(省略规则)
2. 函数返回引用与输入相关时标注
3. 结构体持有引用时标注
4. 实在复杂,考虑用所有权代替引用
5. 用 &'static 前想清楚是否真的需要

// 提示: 如果总是为生命周期头疼,
// 可以考虑返回 String 而不是 &str(简单直观)

Rust 文件与 IO

Rust 文件与 IO

Rust 标准库提供完整的文件读写与 IO 操作能力。

1. 读取文件

use std::fs;

fn main() -> std::io::Result<()> {
    // 一次性读取整个文件
    let content = fs::read_to_string("data.txt")?;
    println!("{}", content);

    // 读取为字节
    let bytes = fs::read("data.bin")?;
    println!("{} 字节", bytes.len());

    Ok(())
}

2. 写入文件

use std::fs;

fn main() -> std::io::Result<()> {
    // 覆盖写入
    fs::write("out.txt", "Hello Rust")?;

    // 追加写入
    use std::io::Write;
    let mut file = fs::OpenOptions::new()
        .append(true)      // 追加模式
        .create(true)      // 不存在则创建
        .open("log.txt")?;
    file.write_all(b"新的一行
")?;

    Ok(())
}

3. 逐行读取

use std::io::{self, BufRead, BufReader};
use std::fs::File;

fn main() -> io::Result<()> {
    let file = File::open("data.txt")?;
    let reader = BufReader::new(file);

    for (i, line) in reader.lines().enumerate() {
        let line = line?;
        println!("{}: {}", i + 1, line);
    }
    Ok(())
}

4. 目录操作

use std::fs;

fn main() -> std::io::Result<()> {
    // 创建目录
    fs::create_dir("new_dir")?;
    fs::create_dir_all("a/b/c")?;    // 递归创建

    // 读取目录
    for entry in fs::read_dir(".")? {
        let entry = entry?;
        let path = entry.path();
        println!("{:?}", path);
    }

    // 删除
    fs::remove_dir("empty_dir")?;
    fs::remove_dir_all("a")?;        // 递归删除

    // 文件操作
    fs::copy("src.txt", "dst.txt")?;
    fs::rename("old.txt", "new.txt")?;
    fs::remove_file("temp.txt")?;

    Ok(())
}

5. 错误处理

use std::fs;

fn main() {
    match fs::read_to_string("missing.txt") {
        Ok(content) => println!("{}", content),
        Err(e) => match e.kind() {
            std::io::ErrorKind::NotFound => {
                println!("文件不存在");
            }
            std::io::ErrorKind::PermissionDenied => {
                println!("没有权限");
            }
            _ => println!("其他错误: {}", e),
        },
    }
}

6. 路径处理(Path)

use std::path::Path;

fn main() {
    let path = Path::new("/tmp/data/file.txt");

    println!("exists: {}", path.exists());
    println!("is_file: {}", path.is_file());
    println!("is_dir: {}", path.is_dir());

    println!("file_name: {:?}", path.file_name());
    println!("extension: {:?}", path.extension());
    println!("parent: {:?}", path.parent());

    // 拼接
    let new = path.join("sub").join("x.log");
    println!("{:?}", new);
}

7. 文本处理常用操作

use std::fs;

fn main() -> std::io::Result<()> {
    let content = fs::read_to_string("data.txt")?;

    // 按行处理
    let mut lines: Vec<&str> = content.lines().collect();

    // 过滤空行
    lines.retain(|l| !l.trim().is_empty());

    // 去重
    lines.sort();
    lines.dedup();

    // 写入
    fs::write("clean.txt", lines.join("
"))?;
    Ok(())
}

Rust 集合与字符串

Rust 集合与字符串

标准库的 Vec、HashMap、HashSet、String 是日常开发的主力容器。

1. Vec 向量

fn main() {
    // 创建
    let mut v: Vec = Vec::new();
    let mut v2 = vec![1, 2, 3];       // 宏创建

    // 添加/删除
    v.push(10);
    v.push(20);
    v.pop();                     // 移除末尾 -> Some(20)
    v.insert(0, 5);              // 插入开头

    // 访问
    let first = &v[0];           // 索引(越界 panic)
    let second = v.get(1);       // Option<&i32>
    println!("{:?}", second);

    // 遍历
    for x in &v { println!("{}", x); }
    for x in &mut v2 { *x += 1; }

    // 常用方法
    v.len();
    v.is_empty();
    v.contains(&10);
    v.sort();
    v.reverse();
    v.iter().map(|x| x * 2).collect::>();
}

2. HashMap 哈希映射

use std::collections::HashMap;

fn main() {
    // 创建
    let mut scores = HashMap::new();
    scores.insert(String::from("数学"), 90);
    scores.insert(String::from("语文"), 85);

    // 读取
    let math = scores.get("数学");        // Option<&i32>
    println!("{:?}", math);               // Some(90)

    // 不存在则插入(entry API)
    scores.entry(String::from("英语"))
        .or_insert(75);

    // 修改
    *scores.get_mut("数学").unwrap() = 95;

    // 遍历
    for (key, value) in &scores {
        println!("{}: {}", key, value);
    }

    // 统计单词出现次数
    let text = "apple banana apple";
    let mut count = HashMap::new();
    for word in text.split_whitespace() {
        *count.entry(word).or_insert(0) += 1;
    }
    println!("{:?}", count);   // {"apple": 2, "banana": 1}
}

3. HashSet 哈希集合

use std::collections::HashSet;

fn main() {
    let mut set = HashSet::new();
    set.insert(1);
    set.insert(2);
    set.insert(1);          // 重复,忽略

    println!("{:?}", set);  // {1, 2}

    // 判断
    set.contains(&1);       // true

    // 集合运算
    let a: HashSet<_> = [1, 2, 3].iter().collect();
    let b: HashSet<_> = [3, 4, 5].iter().collect();

    let union: HashSet<_> = a.union(&b).collect();      // 并
    let intersection: HashSet<_> = a.intersection(&b).collect(); // 交
    let difference: HashSet<_> = a.difference(&b).collect();     // 差

    // 去重
    let nums = vec![1, 2, 2, 3, 3, 3];
    let unique: HashSet = nums.into_iter().collect();
    println!("{:?}", unique);   // {1, 2, 3}
}

4. String 与 &str

fn main() {
    // 创建
    let mut s = String::new();
    let s2 = String::from("hello");
    let s3 = "world".to_string();

    // 追加
    s.push('!');                    // 字符
    s.push_str("hello");            // 字符串
    println!("{}", s);              // !hello

    // 拼接
    let a = String::from("Hello, ");
    let b = String::from("World!");
    let c = a + &b;                 // 注意 &b
    println!("{}", c);              // Hello, World!

    // 格式化
    let name = "张三";
    let greeting = format!("你好, {}!", name);

    // 切片(按字节,注意边界)
    let s4 = "Hello";
    let slice = &s4[0..3];          // "Hel"

    // 遍历
    for c in s4.chars() { }         // 字符
    for b in s4.bytes() { }         // 字节

    // 查找/替换
    let text = "hello world";
    text.contains("world");         // true
    text.replace("world", "rust");  // "hello rust"
    text.to_uppercase();            // "HELLO WORLD"
    text.trim();                    // 去空白
}

5. 集合转换

let v = vec![1, 2, 3];

// Vec -> String
let joined = v.iter()
    .map(|x| x.to_string())
    .collect::>()
    .join(",");          // "1,2,3"

// String -> Vec
let parts: Vec<&str> = "a,b,c".split(',').collect();

// Vec -> HashMap
let pairs = vec![(1, "a"), (2, "b")];
let map: HashMap<_, _> = pairs.into_iter().collect();

6. 常用技巧

// 循环引用集合的迭代
let v = vec![1, 2, 3];
for &x in &v { println!("{}", x); }   // 解引用

// 排序自定义类型
let mut users = vec![(3, "c"), (1, "a"), (2, "b")];
users.sort();                          // 按元组排序

// 最大值/最小值
let max = v.iter().max().unwrap();
let min = v.iter().min().unwrap();

Rust 面向对象

Rust 面向对象编程

Rust 没有传统类继承,但通过 struct + trait 实现面向对象的核心能力。

1. 封装(Encapsulation)

// 字段私有,通过方法访问
pub struct BankAccount {
    balance: f64,        // 私有字段
}

impl BankAccount {
    pub fn new(initial: f64) -> BankAccount {
        BankAccount { balance: initial }
    }

    pub fn deposit(&mut self, amount: f64) {
        self.balance += amount;
    }

    pub fn withdraw(&mut self, amount: f64) -> bool {
        if amount <= self.balance {
            self.balance -= amount;
            true
        } else {
            false
        }
    }

    pub fn balance(&self) -> f64 {
        self.balance
    }
}

fn main() {
    let mut acc = BankAccount::new(100.0);
    acc.deposit(50.0);
    acc.withdraw(30.0);
    println!("余额: {}", acc.balance());   // 120
    // acc.balance = 0;   // 错误!私有
}

2. 多态(Trait 代替继承)

trait Shape {
    fn area(&self) -> f64;
    fn name(&self) -> &str;
}

struct Circle { radius: f64 }
impl Shape for Circle {
    fn area(&self) -> f64 {
        std::f64::consts::PI * self.radius * self.radius
    }
    fn name(&self) -> &str { "圆形" }
}

struct Rectangle { w: f64, h: f64 }
impl Shape for Rectangle {
    fn area(&self) -> f64 { self.w * self.h }
    fn name(&self) -> &str { "矩形" }
}

// 静态分发(泛型)
fn print_area(s: &T) {
    println!("{}面积: {}", s.name(), s.area());
}

// 动态分发(trait 对象)
fn print_all(shapes: &[Box]) {
    for s in shapes {
        println!("{}面积: {}", s.name(), s.area());
    }
}

fn main() {
    let c = Circle { radius: 2.0 };
    let r = Rectangle { w: 3.0, h: 4.0 };
    print_area(&c);    // 圆形面积: 12.566...
    print_area(&r);    // 矩形面积: 12

    let shapes: Vec> = vec![Box::new(c), Box::new(r)];
    print_all(&shapes);
}

3. 默认实现与继承模拟

// trait 默认实现 = 接口默认方法
trait Animal {
    fn name(&self) -> &str;

    fn speak(&self) -> String {
        format!("{} 发出声音", self.name())
    }
}

struct Dog;
impl Animal for Dog {
    fn name(&self) -> &str { "狗" }
    // 使用默认 speak
}

struct Cat;
impl Animal for Cat {
    fn name(&self) -> &str { "猫" }
    fn speak(&self) -> String {
        format!("{} 喵喵叫", self.name())   // 覆盖
    }
}

fn main() {
    println!("{}", Dog.speak());   // 狗 发出声音
    println!("{}", Cat.speak());   // 猫 喵喵叫
}

4. 组合优于继承

// Rust 风格: 用组合代替继承
struct Engine {
    power: u32,
}

struct Car {
    engine: Engine,      // 组合
    brand: String,
}

impl Car {
    fn describe(&self) -> String {
        format!("{} 汽车, {} 马力",
                self.brand, self.engine.power)
    }
}

5. 状态模式(State Pattern)

// 用类型系统表达状态,编译期防错
struct Draft;
struct Published;

struct Post {
    content: String,
    state: std::marker::PhantomData,
}

impl Post {
    fn new() -> Post {
        Post { content: String::new(), state: PhantomData }
    }
    fn add_text(&mut self, text: &str) {
        self.content.push_str(text);
    }
    fn publish(self) -> Post {
        Post { content: self.content, state: PhantomData }
    }
}

impl Post {
    fn content(&self) -> &str { &self.content }
}

fn main() {
    let mut post = Post::new();
    post.add_text("内容");
    let post = post.publish();
    println!("{}", post.content());   // 内容
    // post.add_text("x");   // 错误!Published 无此方法
}

6. Rust OOP 最佳实践

1. 封装: 字段私有 + pub 方法
2. 多态: trait 约束(优先泛型静态分发)
3. 复用: 组合 + trait 默认实现
4. 状态: 用类型系统建模状态(编译期安全)
5. 避免: 过度依赖 Box 动态分发
6. 理念: "关注行为(trait)而非继承层次"

Rust 并发编程

Rust 并发编程

Rust 的并发安全由编译期保证,通过 Send/Sync trait 在编译期杜绝数据竞争。

1. 线程创建

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(50));
    }

    handle.join().unwrap();   // 等待子线程结束
}

2. move 捕获

use std::thread;

fn main() {
    let v = vec![1, 2, 3];

    // move: 所有权移入线程
    let handle = thread::spawn(move || {
        println!("{:?}", v);   // v 在这里可用
    });

    // println!("{:?}", v);   // 错误!v 已移动
    handle.join().unwrap();
}

3. 共享状态(Mutex)

use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    // Arc: 原子引用计数(多线程共享)
    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 h in handles {
        h.join().unwrap();
    }

    println!("结果: {}", *counter.lock().unwrap());   // 10
}

4. 消息传递(mpsc 通道)

use std::sync::mpsc;
use std::thread;
use std::time::Duration;

fn main() {
    // 通道: 发送者 + 接收者
    let (tx, rx) = mpsc::channel();

    // 生产者
    thread::spawn(move || {
        for i in 1..=5 {
            tx.send(i).unwrap();
            thread::sleep(Duration::from_millis(100));
        }
    });

    // 消费者(主线程)
    for received in rx {
        println!("收到: {}", received);
    }
}

// 多生产者
fn multi_producer() {
    let (tx, rx) = mpsc::channel();
    for i in 0..3 {
        let tx = tx.clone();      // 克隆发送者
        thread::spawn(move || {
            tx.send(format!("线程 {}", i)).unwrap();
        });
    }
    drop(tx);    // 关闭原始发送者

    for msg in rx {
        println!("{}", msg);
    }
}

5. Send 与 Sync

// Send: 类型可安全移动到另一个线程
// Sync: 类型可安全被多个线程引用共享

// 大多数类型自动实现
// 原始类型、Vec、String 都 Send + Sync
// Rc(非原子引用计数)不是 Send(用 Arc)

// 自定义类型标注
// 编译期强制检查,违反即报错(安全!)
struct MyData {
    value: i32,
}
// 若 MyData 含 Rc,则不能跨线程

6. 原子类型

use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread;

fn main() {
    let counter = Arc::new(AtomicUsize::new(0));
    let mut handles = vec![];

    for _ in 0..10 {
        let counter = Arc::clone(&counter);
        handles.push(thread::spawn(move || {
            counter.fetch_add(1, Ordering::Relaxed);
        }));
    }
    for h in handles { h.join().unwrap(); }

    println!("{}", counter.load(Ordering::Relaxed));   // 10
}

// 原子类型: AtomicBool、AtomicUsize、AtomicI32 等

7. 并发最佳实践

1. 简单任务: thread::spawn + join
2. 共享数据: Arc + Mutex(或用原子类型)
3. 数据流: mpsc 通道(消息传递优先于共享状态)
4. 大规模并发: 用 Tokio 异步运行时
5. 线程池: rayon(数据并行)等 crate
6. 避免: 持有锁跨 await、死锁顺序不一致

Rust 宏

Rust 宏(Macro)

宏是编译期展开的代码生成,println!、vec! 等实际都是宏。

1. 声明宏(declarative macro)

// macro_rules! 定义声明宏
macro_rules! say_hello {
    () => {
        println!("Hello!");
    };
}

fn main() {
    say_hello!();   // Hello!
}

// 带参数
macro_rules! create_function {
    ($name:ident) => {
        fn $name() {
            println!("函数 {:?} 被调用", stringify!($name));
        }
    };
}

create_function!(foo);
create_function!(bar);

fn main() {
    foo();
    bar();
}

2. 匹配模式

macro_rules! my_vec {
    // 空
    () => {
        Vec::new()
    };
    // 单个元素
    ($x:expr) => {
        {
            let mut v = Vec::new();
            v.push($x);
            v
        }
    };
    // 多个元素
    ($($x:expr),*) => {
        {
            let mut v = Vec::new();
            $(v.push($x);)*
            v
        }
    };
}

fn main() {
    let a = my_vec!();         // []
    let b = my_vec!(1);        // [1]
    let c = my_vec!(1, 2, 3);  // [1, 2, 3]
    println!("{:?}", c);
}

3. 常用宏

// 标准库常用宏
println!("格式化输出");
vec![1, 2, 3];          // 创建 Vec
format!("{}-{}", 1, 2); // 格式化字符串
panic!("出错啦");       // 触发 panic
assert!(true);          // 断言
assert_eq!(1, 1);       // 断言相等
matches!(x, Some(_));   // 模式匹配判断
write!(w, "text");      // 写入 io
include_str!("file");   // 编译期包含文件内容

// 常用宏库
// serde_json::json!({...})
// lazy_static!
// todo!() / unimplemented!()

4. 过程宏(procedural macro)

// 过程宏: 用代码生成代码,更强大
// 三类: 派生宏、属性宏、函数宏

// 派生宏(derive)
#[derive(Debug, Clone, PartialEq)]
struct User { name: String }

// 自定义派生宏示例(serde)
#[derive(serde::Serialize, serde::Deserialize)]
struct Config {
    host: String,
    port: u16,
}

// 属性宏
#[tokio::main]
async fn main() {
    println!("tokio 属性宏");
}

// 函数宏
let json = serde_json::json!({
    "name": "张三",
    "age": 28
});

5. 派生宏实现(示例)

// 用 derive_more 等 crate 简化
// 或自己写过程宏(proc-macro crate)

use proc_macro::TokenStream;

// 简单过程宏
#[proc_macro]
pub fn answer(input: TokenStream) -> TokenStream {
    "42".parse().unwrap()
}

// 使用: my_macro::answer!() → 42

6. 宏 vs 函数

宏:
- 编译期执行,零运行时开销
- 可变参数个数
- 可生成代码
- 调试困难、编译变慢

函数:
- 运行时调用
- 参数数量固定
- 类型检查更强
- 易调试

原则: 优先用函数,需要元编程/变长参数再用宏

Rust 智能指针

Rust 智能指针

智能指针是带所有权与额外行为的指针,Box、Rc、RefCell 是最常用的三种。

1. Box(堆分配)

// Box: 在堆上分配,栈上只存指针
// 用于: 递归类型、大对象、trait 对象

fn main() {
    let b = Box::new(5);
    println!("{}", b);          // 5 自动解引用

    // 递归类型(需要间接引用)
    enum List {
        Cons(i32, Box),
        Nil,
    }

    // trait 对象
    trait Draw { fn draw(&self); }
    struct Circle;
    impl Draw for Circle {
        fn draw(&self) { println!("圆"); }
    }
    let shape: Box = Box::new(Circle);
    shape.draw();
}

2. Rc(引用计数)

// Rc: 单线程多所有权(引用计数)
// 多个变量共享同一数据
use std::rc::Rc;

fn main() {
    let a = Rc::new(5);
    let b = Rc::clone(&a);   // 引用计数 +1
    let c = Rc::clone(&a);   // 计数 +1

    println!("计数: {}", Rc::strong_count(&a));   // 3
    println!("{} {} {}", a, b, c);
}

// 场景: 图结构、共享配置、观察者模式
// 注意: Rc 不是 Send,不能跨线程

3. RefCell(内部可变性)

// RefCell: 运行时借用检查(编译期规则放宽)
// 场景: 需要在不可变引用下修改
use std::cell::RefCell;

struct MockMessenger {
    messages: RefCell>,
}

impl MockMessenger {
    fn send(&self, msg: String) {
        // &self 下修改内部数据
        self.messages.borrow_mut().push(msg);
    }

    fn count(&self) -> usize {
        self.messages.borrow().len()
    }
}

fn main() {
    let m = MockMessenger {
        messages: RefCell::new(vec![]),
    };
    m.send(String::from("hi"));
    m.send(String::from("hello"));
    println!("{}", m.count());   // 2
}

4. Rc + RefCell 组合

// 循环引用/共享可变数据
use std::rc::Rc;
use std::cell::RefCell;

fn main() {
    // 多个持有者 + 可变
    let shared = Rc::new(RefCell::new(5));

    let a = Rc::clone(&shared);
    let b = Rc::clone(&shared);

    *a.borrow_mut() += 10;    // 修改

    println!("{}", b.borrow());   // 15(共享可见)
}

5. Arc(线程安全 Rc)

// Arc: 原子引用计数,可跨线程
use std::sync::Arc;
use std::thread;

fn main() {
    let data = Arc::new(vec![1, 2, 3]);

    let mut handles = vec![];
    for _ in 0..3 {
        let data = Arc::clone(&data);
        handles.push(thread::spawn(move || {
            println!("{:?}", data);
        }));
    }
    for h in handles { h.join().unwrap(); }
}

// Arc + Mutex = 线程安全共享可变数据

6. 其他智能指针

Cow: 写时复制(借用或拥有)
Cell: 值语义的内部可变性(Copy 类型)
MutexGuard / RwLockGuard: 锁守卫
String / Vec: 也是智能指针(拥有堆数据)
Pin: 固定地址(异步中使用)
Weak: 弱引用(防循环引用)

7. 选型指南

单所有权: Box
多所有权(单线程): Rc
多所有权(多线程): Arc
内部可变性(单线程): RefCell / Cell
内部可变性(多线程): Mutex / RwLock
组合: Rc>、Arc>(常用)

注意: 优先用所有权与借用,智能指针是"最后手段"

Rust 异步编程

Rust 异步编程

Rust 异步基于 async/await,配合 Tokio 运行时,适合 IO 密集型高并发服务。

1. async/await 基础

// async fn: 返回 Future,惰性执行
async fn hello() -> String {
    String::from("Hello")
}

// 需要运行时执行
// Cargo.toml: tokio = { version = "1", features = ["full"] }

#[tokio::main]
async fn main() {
    let result = hello().await;   // 等待完成
    println!("{}", result);
}

2. 并发执行

use tokio::time::{sleep, Duration};

async fn task(name: &str, secs: u64) {
    println!("{} 开始", name);
    sleep(Duration::from_secs(secs)).await;
    println!("{} 完成", name);
}

#[tokio::main]
async fn main() {
    // 顺序执行(共 3 秒)
    task("A", 1).await;
    task("B", 2).await;

    // 并发执行(共 2 秒)
    let (a, b) = tokio::join!(
        task("C", 1),
        task("D", 2),
    );

    // join handle 方式
    let h1 = tokio::spawn(task("E", 1));
    let h2 = tokio::spawn(task("F", 1));
    h1.await.unwrap();
    h2.await.unwrap();
}

3. 异步 HTTP 请求

// Cargo.toml
// reqwest = { version = "0.12", features = ["json"] }
// tokio = { version = "1", features = ["full"] }

use reqwest;

#[tokio::main]
async fn main() -> Result<(), Box> {
    // GET 请求
    let resp = reqwest::get("https://httpbin.org/get")
        .await?
        .text()
        .await?;
    println!("{}", resp);

    // JSON 请求
    let json: serde_json::Value = reqwest::get("https://httpbin.org/json")
        .await?
        .json()
        .await?;
    println!("{:?}", json);

    Ok(())
}

4. 异步 Web 服务

// Cargo.toml
// axum = "0.7"
// tokio = { version = "1", features = ["full"] }

use axum::{routing::get, Router, Json};
use serde_json::{json, Value};

async fn hello() -> &'static str {
    "Hello, Axum!"
}

async fn api() -> Json {
    Json(json!({ "status": "ok" }))
}

#[tokio::main]
async fn main() {
    let app = Router::new()
        .route("/", get(hello))
        .route("/api", get(api));

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000")
        .await.unwrap();
    println!("监听 3000 端口");
    axum::serve(listener, app).await.unwrap();
}

5. 异步数据竞争防护

// 共享状态: Arc>
use std::sync::{Arc, Mutex};
use axum::{routing::get, Router, extract::State};

async fn counter(State(state): State>>) -> String {
    let mut count = state.lock().unwrap();
    *count += 1;
    format!("计数: {}", count)
}

#[tokio::main]
async fn main() {
    let state = Arc::new(Mutex::new(0));
    let app = Router::new()
        .route("/count", get(counter))
        .with_state(state);
    // ...
}

6. 异步陷阱与最佳实践

1. 不要在 async 中调用阻塞函数(用 tokio::task::spawn_blocking)
2. 不要在 .await 时持有 std Mutex 锁
3. 用 #[tokio::main] 简化入口
4. 长任务用 tokio::spawn 隔离
5. 定时任务用 tokio::time
6. 测性能: 默认单线程调 multithread 特性

// 阻塞任务处理
#[tokio::main]
async fn main() {
    let heavy = tokio::task::spawn_blocking(|| {
        // CPU 密集/阻塞代码
        std::thread::sleep(std::time::Duration::from_secs(1));
        42
    });
    println!("{}", heavy.await.unwrap());
}

7. 异步 vs 多线程选择

异步(async + Tokio):
- IO 密集型(网络、文件、数据库)
- 高并发连接(数万)
- 资源占用低

多线程(thread + Arc):
- CPU 密集型计算
- 简单任务
- 无 tokio 依赖

通用: 服务器开发几乎都用 async + Tokio
第 1 / 29 节