本工具使用的开源库

本工具代码中捆绑了 1 个开源库。

Rust 速查 — 简明参考

Rust 2021 版语法、所有权、错误处理与最常用 std API 速查手册,覆盖约 80% 日常场景。

Rs

Rust Rust 2021 edition

rustc / cargo · 编译型 · 系统级 · 函数式 · 并发 · 静态 · 强类型 · affine(移动语义)

学习路径

先学会 cargo new/run 与 println! → 掌握变量绑定、所有权与借用(Rust 核心)→ 深入 match、函数与闭包 → 用 Vec/HashMap/迭代器组织数据 → 理解 trait 与泛型 → 用 Result 与 ? 处理错误 → 用线程与 channel 写并发 → 再按需学网络、时间与构建测试。FAQ 节适合回头避坑。

1.Hello World 与构建环境

运行 Rust 程序、cargo 项目与工具链。

最小程序

fn main 是入口。println! 宏输出。语句以分号结尾。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 新建项目:
// cargo new hello
// cd hello
// 编辑 src/main.rs:
fn main() {
println!("Hello, world!");
}
// 运行:
// cargo run
// 输出:Hello, world!
// 要点:
// fn 关键字定义函数
// println! 是宏(带 !)
// main 返回 () 类型
// 表达式末尾分号可选(见函数节)

运行与构建

cargo run 编译并运行、cargo build 生成二进制、cargo check 快速检查。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 编译并运行:
// cargo run
// 构建(调试):
// cargo build
// 快速检查(不生成二进制):
// cargo check
// 发布构建(优化):
// cargo build --release
// 产物位置:
// target/debug/hello
// target/release/hello
// 单文件直接编译:
// rustc main.rs
// 生成可执行文件 main
// 大项目始终用 cargo

cargo 项目

cargo new 初始化项目。Cargo.toml 声明包与依赖。src/ 放源码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 创建二进制项目:
// cargo new hello --bin
// 创建库项目:
// cargo new mylib --lib
// Cargo.toml 核心:
// [package]
// name = "hello"
// version = "0.1.0"
// edition = "2021"
// 结构:
// Cargo.toml 清单
// src/main.rs 入口
// src/lib.rs 库入口
// target/ 构建产物
// 文档生成:
// cargo doc --open
// 构建缓存 target 可删

edition

edition 声明语言版本。2021 是当前版本。rust-version 声明最低工具链。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Cargo.toml:
// [package]
// name = "app"
// version = "0.1.0"
// edition = "2021" // 语言版
// rust-version = "1.70" // 最低 rustc
// 查看当前版本:
// rustc --version
// 升级 edition:
// cargo fix --edition
// 各版本:
// 2015(旧)/ 2018 / 2021
// edition 差异:
// 关键字的可用性
// 宏与预导入差异
// 同一项目一次只用一种

输出宏

println!/print! 输出、eprintln! 错误流、format! 生成字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
fn main() {
let name = "Rust";
let ver = 1.82;
// 占位符:
println!("Hello, {}!", name);
println!("版本: {}", ver);
// 编号与命名:
println!("{0} {1} {0}", "a", "b");
println!("{name} v{ver}", name = name, ver = ver);
// 格式控制:
println!("{:>10}", "右对齐"); // 宽度
println!("{:.2}", 3.14159); // 精度
println!("{:b}", 10); // 二进制
println!("{:?}", vec![1, 2]); // Debug
// 无换行:
print!("连续");
// 错误流:
eprintln!("出错了");
}

命令行参数

std::env::args 获取命令行参数。第一个是程序路径。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use std::env;
fn main() {
// 收集参数:
let args: Vec<String> = env::args().collect();
println!("共 {} 个参数", args.len());
for a in &args {
println!("{}", a);
}
// 业务参数从第 1 个开始:
// args[0] 是程序路径
// 忽略非法 UTF-8 用 args_os:
// env::args_os()
// 常见用法:
// let name = args.get(1).unwrap();
// 复杂解析用 clap 库
}

多文件

mod 声明模块。子模块文件或目录。use 导入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// src/main.rs:
mod math; // 声明模块
use math::add;
fn main() {
println!("{}", add(1, 2));
}
// src/math.rs:
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
// 或目录:
// src/math/mod.rs
// src/math/utils.rs
// 导出:
// pub fn / pub struct
// 私有默认:
// 同模块可访问
// 子模块用 super:: 引用父级

直接编译

rustc 编译单个文件。无 cargo 依赖。适合练习与小脚本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 编译:
// rustc hello.rs
// 运行:
// ./hello
// 带输出名:
// rustc hello.rs -o app
// 优化:
// rustc -O hello.rs
// 调试信息:
// rustc -g hello.rs
// 警告全开:
// rustc -D warnings hello.rs
// 查看版本:
// rustc --version
// 限制:
// 无依赖管理
// 标准库外的 crate
// 需 cargo 处理
// 适合教学与单文件实验

2.变量与绑定

let 绑定、可变性、遮蔽、作用域与类型。

let 与 mut

let 绑定变量默认不可变。mut 声明可变。Rust 变量默认不可变。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
fn main() {
// 不可变绑定:
let x = 5;
// x = 6; // 错误:不可变
// 可变绑定:
let mut y = 5;
y = 6; // 允许
println!("{}", y);
// 显式类型:
let n: u32 = 42;
// 先声明后赋值:
let mut z;
z = 10;
// 未使用警告:
// 用 _ 前缀忽略
let _unused = 0;
}

遮蔽

同名 let 遮蔽旧绑定。可改变类型。不同于 mut 修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
fn main() {
let x = 5;
let x = x + 1; // 遮蔽
let x = x * 2;
println!("{}", x); // 12
// 改变类型:
let spaces = " ";
let spaces = spaces.len(); // usize
// 与 mut 区别:
// 遮蔽是新建绑定
// mut 是修改原值
// 遮蔽后旧值不可访问
// 作用域内遮蔽:
{
let x = 99; // 内层遮蔽
println!("{}", x); // 99
}
println!("{}", x); // 12
}

const 与 static

const 编译期常量。static 静态变量。命名用全大写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 常量:
const MAX_SIZE: u32 = 100;
const PI: f64 = 3.141592;
// 静态变量(有固定地址):
static APP_NAME: &str = "demo";
// 静态可变(unsafe):
static mut COUNTER: u32 = 0;
fn inc() {
unsafe {
COUNTER += 1; // 需 unsafe
}
}
// 区别:
// const 编译期内联,无地址
// static 有固定内存地址
// static mut 访问需 unsafe
// 现代做法:
// 优先 const
// 全局状态用互斥锁
// 常量表达式可计算

类型推断

编译器根据上下文推断类型。必要时显式标注。整数默认 i32。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fn main() {
// 自动推断:
let x = 42; // i32(默认)
let y = 3.14; // f64(默认)
// 上下文推断:
let mut v = Vec::new();
v.push(1); // 推断 Vec<i32>
// 显式标注:
let n: u64 = 42;
let f: f32 = 3.14;
// 方法返回值定类型:
let s: u32 = "42".parse().unwrap();
// 推断失败需标注
// 整数类型默认 i32
// 浮点默认 f64

解构绑定

let 支持模式解构。元组、结构体、数组一次性取出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
fn main() {
// 元组解构:
let (a, b, c) = (1, 2, 3);
println!("{} {} {}", a, b, c);
// 数组解构:
let [x, y, _] = [10, 20, 30];
// 结构体解构:
struct Point { x: i32, y: i32 }
let p = Point { x: 1, y: 2 };
let Point { x, y } = p;
// 重命名:
let Point { x: px, y: py } = p;
// 剩余:
let (first, rest..) = (1, 2, 3, 4);
// 通配符 _ 忽略:
let (_, b2) = (1, 2);
}

作用域

块作用域 {}。变量生命周期。内层可访问外层。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fn main() {
let outer = 1;
{
// 内层可访问外层:
println!("{}", outer);
let inner = 2;
println!("{}", inner);
}
// println!("{}", inner); // 错误:已离开作用域
// 同作用域内不能同名:
// 遮蔽需嵌套作用域
// 所有权随作用域结束
// 释放顺序(逆序):
// Drop 在作用域结束时调用
// 提前结束用 drop()

命名规范

Rust 命名约定。snake_case 变量/函数、CamelCase 类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 变量/函数:snake_case
let user_name = "nick";
fn get_user() {}
// 类型/枚举/trait:CamelCase
struct UserAccount {}
enum ColorChoice {}
trait Displayable {}
// 常量/静态:SCREAMING_SNAKE
const MAX_ITEMS: usize = 100;
// 私有标识可加 _ 前缀
// 泛型参数:单大写字母 T
// 生命周期:'a 'b
// 内置风格:
// is_ / has_ 前缀布尔函数
// into_ / to_ / as_ 转换
// 编译器 lint 检查命名

类型转换

as 做显式数值转换。From/Into trait 做安全转换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
fn main() {
// as 数值转换:
let i: i32 = 42;
let u: u64 = i as u64;
let f: f64 = i as f64;
// 截断风险:
let big: u16 = 300;
let small: u8 = big as u8; // 44
// From/Into:
let s = String::from("hello");
let s2: String = "hi".into();
// 精确转换:
let x: u8 = 255;
let y: u32 = x.into(); // From<u8> for u32
// 字符串解析:
let n: i32 = "42".parse().unwrap();
// 显示要求:
// let n: i32 = "42".parse()?;

3.类型系统

基础类型、元组、结构体与枚举。

基础类型

整数、浮点、布尔、字符。标量类型与长度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
fn main() {
// 整数:
let i: i32 = -10; // 有符号
let u: u32 = 10; // 无符号
// 浮点:
let f: f32 = 1.5;
let d: f64 = 3.14159;
// 布尔:
let b: bool = true;
let c: bool = false;
// 字符(Unicode):
let ch: char = '中';
let emoji: char = '🚀';
// 字符串片段:
let s: &str = "text";
// 整数默认 i32,浮点默认 f64
// char 占 4 字节(Unicode 标量)

整数类型

i8-u128、usize/isize。有符号无符号。平台相关。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fn main() {
// 有符号:i8 i16 i32 i64 i128
// 无符号:u8 u16 u32 u64 u128
// 平台相关:usize isize
let a: i8 = -128; // 范围 -128..127
let b: u8 = 255; // 范围 0..255
let c: i64 = 9_223_372_036_854_775_807;
// 字面量后缀:
let d = 255u8;
let e = 1_000_000i64; // 下划线分隔
// 十六进制/二进制:
let h = 0xff;
let bin = 0b1010;
// usize 用途:
// 索引、长度、指针大小
// 溢出检查(调试构建 panic)

浮点数

f32/f64 符合 IEEE 754。NaN、无穷、运算。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
fn main() {
let a: f64 = 3.14;
let b: f64 = 2.0;
// 运算:
let sum = a + b;
let div = a / b;
let pow = a.powi(2); // 幂
let sqrt = a.sqrt();
// 特殊值:
let inf = f64::INFINITY;
let neg_inf = f64::NEG_INFINITY;
let nan = f64::NAN;
// 判断:
// nan.is_nan()
// inf.is_infinite()
// 注意:
// NaN != NaN
// 浮点不适合精确比较
// 精度:
// f32 约 7 位十进制
// f64 约 15-16 位

char 类型

char 是 Unicode 标量值,占 4 字节。单引号字面量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
fn main() {
let c = 'A';
let zh = '中';
let emoji = '😀';
// 转义:
let tab = '\t';
let quote = '\'';
let newline = '\n';
// Unicode 码点:
let cp = '\u{1F600}'; // 😀
// 操作:
println!("{}", c.is_ascii());
println!("{}", zh.is_alphabetic());
// 与数字:
let n = '9' as u8; // 57
// char 与 String:
// 字符转字符串:
let s = c.to_string();
// 一个 char 不是 &str

元组

固定长度异构集合。索引访问。解构。空元组是 ()。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
fn main() {
// 定义:
let t = (1, "two", 3.0);
// 索引访问:
println!("{}", t.0); // 1
println!("{}", t.1); // "two"
// 类型标注:
let t2: (i32, bool) = (5, true);
// 解构:
let (a, b, c) = t;
// 单元素元组:
let one = (42,); // 注意逗号
// 空元组/单元类型:
let u: () = ();
// () 是函数默认返回
// 常用:
// 多值返回 (val, err)
// 交换: (a, b) = (b, a)

结构体

struct 定义命名字段。实例化、访问、更新语法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
struct User {
name: String,
age: u8,
active: bool,
}
fn main() {
// 实例化:
let mut u = User {
name: String::from("nick"),
age: 30,
active: true,
};
// 访问字段:
println!("{}", u.name);
u.age += 1; // 需 mut
// 更新语法:
let u2 = User { age: 20, ..u };
// 元组结构体:
struct Point(i32, i32);
let p = Point(1, 2);
println!("{}", p.0);
// 单元结构体:
struct Unit;
}

枚举

enum 定义多种变体。可携带数据。match 穷尽处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
enum Message {
Quit,
Move { x: i32, y: i32 }, // 结构体变体
Write(String), // 元组变体
ChangeColor(u8, u8, u8),
}
fn main() {
let m = Message::Write(String::from("hi"));
// match 穷尽匹配:
match m {
Message::Quit => println!("退出"),
Message::Move { x, y } => {
println!("移动 {} {}", x, y);
}
Message::Write(s) => println!("{}", s),
Message::ChangeColor(r, g, b) => {
println!("颜色 {}-{}-{}", r, g, b);
}
}
// 枚举可带泛型/方法
// Option/Result 也是枚举

单元类型

() 表示没有值。函数默认返回 ()。无参无返回的约定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
fn main() {
// () 类型:
let unit: () = ();
// 函数默认返回 ():
fn say() {}
// 等同:
fn say2() -> () {}
// 表达式返回 ():
let r = { let x = 1; }; // 空块
// 用法:
// 作为类型参数:
// Result<T, ()> 只关心错误
// HashMap<K, ()> 当集合
// 泛型占位:
// 不关心具体类型
// 打印 Debug:
println!("{:?}", ());

4.所有权与引用

所有权、借用、引用与切片。Rust 内存安全核心。

所有权

每个值只有一个所有者。离开作用域自动释放。移动而非拷贝。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fn main() {
// 所有权规则:
// 1. 每个值只有一个所有者
// 2. 所有者离开作用域释放
// 3. 转移所有权叫移动
let s1 = String::from("hello");
let s2 = s1; // 移动:s1 失效
// println!("{}", s1); // 错误:已移动
println!("{}", s2);
// 拷贝类型(栈上 Copy):
let a = 5;
let b = a; // 拷贝,都有效
println!("{} {}", a, b);
// 函数传参也转移:
// fn take(s: String) {}
// 取回用返回值

引用

&T 不可变引用,不转移所有权。借用后原值仍可用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
fn main() {
let s = String::from("hello");
// 不可变引用:
let len = calculate_length(&s);
println!("{}", len); // 5
println!("{}", s); // 仍可用
}
fn calculate_length(s: &String) -> usize {
s.len() // 借用,不拥有
}
// 引用规则:
// &T 只读借用
// 引用不转移所有权
// 引用默认不可变
// 多个不可变引用可并存
// 引用离开作用域不释放值
// 常见:
// 参数用 &str / &T 避免拷贝

可变引用

&mut T 可变引用。同一作用域一个变量只能有一个可变引用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
fn main() {
let mut s = String::from("hello");
change(&mut s);
println!("{}", s); // hello!
}
fn change(s: &mut String) {
s.push_str("!");
}
// 规则:
// 可变引用 &mut T
// 同一作用域只有一个
// 不可变与可变不能并存:
// let r1 = &s;
// let r2 = &mut s; // 错误
// 数据竞争编译期禁止:
// 读多写少场景
// 借用结束后才可再借
// 花括号可缩短借用范围

解引用

* 运算符访问引用指向的值。解引用与引用配对。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
fn main() {
let x = 5;
let r = &x; // 引用
// 解引用访问值:
println!("{}", *r);
// 解引用赋值:
let mut y = 5;
let r2 = &mut y;
*r2 += 1; // 修改 y
println!("{}", y); // 6
// 方法调用自动解引用:
// s.len() 无需 (*s).len()
// 索引底层也是解引用
// 引用比较:
// == 比较值还是引用?
// 常比较解引用后的值
// 悬挂引用编译器拒绝

生命周期

'a 标注引用有效范围。借用检查器保证引用有效。省略规则。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 生命周期标注:
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("s");
let r = longest(&s1, &s2);
println!("{}", r);
}
// 规则:
// 'a 表示引用的有效范围
// 返回值生命周期取输入交集
// 结构体可存引用:
// struct X<'a> { part: &'a str }
// 省略规则:
// 单输入省略为输出
// 方法省略 self 生命周期
// 多数情况无需显式标注

切片

&[T] 是连续元素的引用。字符串切片 &str。无所有权。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fn main() {
// 数组切片:
let arr = [1, 2, 3, 4, 5];
let s: &[i32] = &arr[1..4]; // [2,3,4]
println!("{:?}", s);
// 字符串切片:
let st = String::from("hello");
let part: &str = &st[0..2]; // "he"
// 边界在字符边界,否则 panic
// 全量切片:
let all = &arr[..];
// 常见:
// 函数参数用 &[T] 而非 Vec
// &str 是 String 的借用
// 切片长度编译期未知
// 切片传引用不拷贝

Deref 自动解引用

Deref trait 让 &String 自动变 &str 等。参数多态便捷。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
use std::ops::Deref;
fn main() {
let s = String::from("hello");
// &String 自动变 &str:
let t: &str = &s;
// 函数参数自动转换:
fn takes_str(s: &str) {}
let s2 = String::from("world");
takes_str(&s2); // 自动解引用
// 自定义 Deref:
struct MyBox<T>(T);
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
// 方法调用也自动:
// my_box.len() 会逐层 deref
// 转换链:&MyBox<T> -> &T

Copy 类型

Copy trait 类型赋值是复制而非移动。整数、浮点、bool、char 等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
fn main() {
// Copy 类型:赋值后仍可用
let a = 5;
let b = a; // 复制
println!("{} {}", a, b); // 都可
// Copy 类型清单:
// 所有整数/浮点/bool/char
// 元组(元素全 Copy)
// 数组
// &T 引用(是 Copy)
// 非 Copy:
// String、Vec、Box
// 结构体默认非 Copy:
#[derive(Clone, Copy)]
struct Point { x: i32, y: i32 }
let p1 = Point { x: 1, y: 2 };
let p2 = p1; // Copy
println!("{} {}", p1.x, p2.x);
// 判断:
// 离开作用域无 Drop 才能 Copy
// 克隆需要显式 .clone()

5.流程控制

if、match、循环。Rust 控制流是表达式。

if 表达式

if/else 是表达式,可返回值。条件无需括号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
fn main() {
let n = 7;
// 分支:
if n > 0 {
println!("正数");
} else if n == 0 {
println!("零");
} else {
println!("负数");
}
// if 是表达式:
let sign = if n > 0 { "+" } else { "-" };
println!("{}", sign);
// 条件不需要括号
// 必须 bool 类型
// 分支返回类型必须一致
// 无 else 的 if 返回 ()

match

match 穷尽匹配。每个分支是表达式。可匹配模式、范围、守卫。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
fn main() {
let x = 3;
// 匹配字面值:
match x {
1 => println!("一"),
2 | 3 => println!("二或三"), // 或
4..=6 => println!("四到六"), // 范围
_ => println!("其他"), // 通配
}
// 绑定与守卫:
let num = Some(10);
match num {
Some(n) if n > 5 => println!("大数 {}", n),
Some(n) => println!("小数 {}", n),
None => println!("无"),
}
// 必须穷尽(无 _ 会编译错误)
// match 可返回表达式值

while 循环

while 条件循环。条件为真时反复执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
fn main() {
let mut n = 3;
// 计数循环:
while n > 0 {
println!("{}", n);
n -= 1;
}
// 条件循环:
let mut line = String::new();
while line.trim() != "quit" {
line.clear();
// 读取输入...
break; // 示例直接跳出
}
// while 循环没有索引
// 遍历集合优先 for
// 需索引场景用:
// 计数器 + while
// while 返回 ()

for 循环

for 遍历范围与迭代器。Rust 首选循环方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
fn main() {
// 范围:
for i in 0..5 {
println!("{}", i); // 0..4
}
// 含端点:
for i in 0..=5 {
println!("{}", i); // 0..5
}
// 遍历数组:
let arr = [10, 20, 30];
for v in &arr {
println!("{}", v);
}
// 需索引:
for (i, v) in arr.iter().enumerate() {
println!("{}: {}", i, v);
}
// 倒序:
for i in (0..3).rev() {}
// 遍历集合不转移所有权
// 移动遍历用 into_iter

无限循环

loop 无限循环直到 break。可返回值。可带标签。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
fn main() {
// 无限循环:
let mut count = 0;
let result = loop {
count += 1;
if count == 3 {
break count * 10; // 返回 30
}
};
println!("{}", result);
// 标签跳出外层:
'outer: loop {
loop {
break 'outer; // 跳出外层
}
}
// 用途:
// 重试、轮询、事件循环
// 与 while true 等同
// loop 更惯用可返回值

break 与 continue

break 退出循环。continue 跳过本轮。可配合标签。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
fn main() {
let mut n = 0;
loop {
n += 1;
// 跳过偶数:
if n % 2 == 0 {
continue;
}
if n > 7 {
break;
}
println!("{}", n); // 1 3 5 7
}
// continue 跳出当前迭代
// break 带值:
let v = loop { break 42; };
// 嵌套标签:
'a: for i in 0..3 {
for j in 0..3 {
if i + j == 2 {
continue 'a; // 继续外层
}
}
}
}

if let

if let 简化单模式匹配。只关心一种变体时使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
fn main() {
let opt = Some(5);
// 匹配单模式:
if let Some(v) = opt {
println!("值 {}", v);
}
// 带 else:
if let Some(v) = opt {
println!("有值 {}", v);
} else {
println!("无值");
}
// 其他模式:
let res: Result<i32, &str> = Ok(10);
if let Ok(v) = res {
println!("成功 {}", v);
}
// 对应 match:
// match opt {
// Some(v) => ...,
// _ => (),
// }
// 更简洁、只关注一种情形
// 非穷尽、可组合

while let

while let 循环直到模式不再匹配。迭代处理集合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
fn main() {
let mut stack = vec![1, 2, 3];
// 不断弹出直到空:
while let Some(top) = stack.pop() {
println!("{}", top); // 3 2 1
}
// 处理字符序列:
let mut chars = "abc".chars();
while let Some(c) = chars.next() {
println!("{}", c);
}
// 对应 loop + match:
// loop {
// match v.next() {
// Some(x) => ...
// None => break,
// }
// }
// 迭代器可迭代对象
// 条件复杂时用 loop

6.函数

函数定义、返回值、所有权传递、闭包与泛型。

函数定义

fn 定义函数。参数需类型标注。函数体是表达式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 无返回值:
fn greet(name: &str) {
println!("你好 {}", name);
}
// 有返回值:
fn add(a: i32, b: i32) -> i32 {
a + b // 最后一个表达式
}
// 显式 return:
fn early(x: i32) -> i32 {
if x < 0 {
return 0;
}
x * 2
}
fn main() {
greet("Rust");
println!("{}", add(1, 2));
println!("{}", early(-5));
}
// 返回 () 可省略 ->

返回值

最后一个表达式是返回值。分号区分语句与表达式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
fn main() {
let x = five();
println!("{}", x); // 5
let y = with_semi();
println!("{:?}", y); // ()
}
fn five() -> i32 {
5 // 表达式,返回值
}
fn with_semi() {
5; // 语句,返回 ()
}
// 要点:
// 表达式 = 有值的代码
// 语句 = 以分号结尾
// 无分号 = 返回该值
// 块是表达式:
let n = { let a = 1; a + 2 }; // 3
// if/match/loop 都是表达式

参数

参数默认不可变。模式解构参数。引用参数避免拷贝。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 引用参数:
fn show(name: &str) {
println!("{}", name);
}
// 可变参数需 mut:
fn append(v: &mut Vec<i32>) {
v.push(1);
}
// 元组解构参数:
fn sum((a, b): (i32, i32)) -> i32 {
a + b
}
fn main() {
show("nick");
let mut v = vec![];
append(&mut v);
println!("{}", sum((1, 2)));
}
// 参数是值的拷贝/移动
// 大类型传引用
// 需要修改传 &mut
// 返回新值避免引用

所有权参数

传值即转移所有权。借用可复用。需要时返回所有权。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
fn takes(s: String) {
println!("{}", s); // s 在此被使用后释放
} // s 离开作用域,释放
fn main() {
let s = String::from("hi");
takes(s);
// println!("{}", s); // 错误:已移动
// 取回所有权:
let s2 = String::from("keep");
let s2 = give_back(s2);
println!("{}", s2);
}
fn give_back(s: String) -> String {
s // 返回转移回来
}
// 替代:
// 借用 &str 通常更合适
// 需要所有权才传值
// 返回多个值用元组

借用参数

&T 只读借用、&mut T 可变借用。避免转移所有权。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 只读借用:
fn len(s: &str) -> usize {
s.len()
}
// 多个只读借用可并存:
fn print_two(a: &str, b: &str) {
println!("{} {}", a, b);
}
// 可变借用:
fn push_item(v: &mut Vec<i32>, x: i32) {
v.push(x);
}
fn main() {
let s = String::from("abc");
println!("{}", len(&s));
println!("{}", s); // 借用后仍可用
let mut v = vec![1];
push_item(&mut v, 2);
println!("{:?}", v);
}
// &str 参数比 &String 更通用

闭包

闭包捕获环境变量。|参数| 语法。可存变量、传函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
fn main() {
// 定义:
let add = |a: i32, b: i32| a + b;
println!("{}", add(1, 2));
// 捕获外部变量:
let factor = 3;
let mul = |x: i32| x * factor;
println!("{}", mul(5)); // 15
// 闭包可修改捕获(需 mut):
let mut count = 0;
let mut inc = || {
count += 1;
count
};
println!("{}", inc()); // 1
// 作为参数:
let evens: Vec<i32> =
(1..=6).filter(|x| x % 2 == 0).collect();
println!("{:?}", evens);
// 移入 move 闭包见并发节

函数指针

fn 类型引用普通函数。fn(T) -> U 语法。闭包转 fn。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
fn add_one(x: i32) -> i32 {
x + 1
}
// 函数指针类型:
fn apply(f: fn(i32) -> i32, x: i32) -> i32 {
f(x)
}
fn main() {
let f: fn(i32) -> i32 = add_one;
println!("{}", f(10)); // 11
println!("{}", apply(add_one, 10));
// 不捕获的闭包可转 fn:
let c = |x: i32| x * 2;
let g: fn(i32) -> i32 = c;
println!("{}", g(5));
// 函数数组/向量:
let funcs = [add_one, add_one];
// 泛型场景用 Fn trait

泛型函数

泛型参数 <T> 抽象类型。可加约束。类型推断。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 泛型函数:
fn largest<T: PartialOrd>(list: &[T]) -> &T {
let mut max = &list[0];
for item in list {
if item > max {
max = item;
}
}
max
}
fn main() {
let nums = vec![34, 50, 25];
println!("{}", largest(&nums));
let chars = vec!['y', 'm', 'a'];
println!("{}", largest(&chars));
}
// T: PartialOrd 是 trait 约束
// 多个参数:fn pair<T, U>
// 调用时自动推断类型
// 也可显式:largest::<i32>(&nums)
// 泛型不损失性能(单态化)

7.字符串

&str 与 String、操作、格式化、解析与遍历。

&str 与 String

&str 是借用字符串,String 是拥有所有权的可增长字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
fn main() {
// &str 字符串字面量:
let s: &str = "hello";
// String 拥有所有权:
let mut owned = String::from("hello");
owned.push_str(" world");
// &str -> String:
let a: String = s.to_string();
let b: String = String::from(s);
// String -> &str(借用):
let c: &str = &owned;
let d: &str = owned.as_str();
// 区别:
// &str 固定长度,不拥有数据
// String 可增长,堆上分配
// 参数优先用 &str
// 需要拥有再转 String

String 操作

追加、插入、替换、删除。修改 String 的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
fn main() {
let mut s = String::from("hello");
// 追加:
s.push_str(", world"); // 字符串
s.push('!'); // 单个字符
// 插入:
s.insert(5, ' ');
// 替换:
let t = s.replace("hello", "hi");
// 删除:
s.pop(); // 移除末尾
s.truncate(5); // 截断
// 清空:
s.clear();
// 拼接:
let s1 = String::from("a");
let s2 = String::from("b");
let s3 = s1 + &s2; // s1 被移动
let s4 = format!("{} {}", s3, "c");
// 长度:s.len() 字节数
}

格式化

format! 拼接字符串。占位符与格式控制。安全高效。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
fn main() {
let name = "Nick";
let age = 30;
// 基础拼接:
let s = format!("{} 今年 {} 岁", name, age);
println!("{}", s);
// 编号/命名:
format!("{0} {1} {0}", "a", "b");
format!("{name}-{age}", name = name, age = age);
// 对齐与宽度:
format!("{:>8}", "right"); // 右对齐
format!("{:<8}", "left"); // 左对齐
format!("{:^8}", "center");
// 数字格式:
format!("{:.2}", 3.14159); // 3.14
format!("{:+}", 42); // +42
format!("{:08b}", 10); // 二进制补零
format!("{:#x}", 255); // 0xff
// Debug 调试格式:
format!("{:?}", vec![1, 2]);

字符串切片

&s[a..b] 按字节切片。必须在字符边界,否则 panic。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
fn main() {
let s = String::from("hello 世界");
// 字节切片:
let part = &s[0..5]; // "hello"
println!("{}", part);
// 字符边界:
// "世界" 每个字符 3 字节
let w = &s[6..12]; // "世界"
// 错误的边界 panic:
// let bad = &s[0..6]; // 非字符边界
// 安全遍历方式:
for c in s.chars() {
println!("{}", c);
}
// 取单个字符:
let first = s.chars().next();
// 按行:
for line in s.lines() {}
// 索引是字节位置,非字符位置

字符串遍历

chars() 按字符、bytes() 按字节、char_indices 带位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
fn main() {
let s = "你好Rust";
// 按字符遍历:
for c in s.chars() {
println!("{}", c);
}
// 按字节遍历:
for b in s.bytes() {
println!("{:02x}", b);
}
// 字符 + 字节偏移:
for (i, c) in s.char_indices() {
println!("{} at {}", c, i);
}
// 按行:
for line in "a\nb\n".lines() {
println!("<{}", line);
}
// 分割:
for part in "a,b,c".split(",") {
println!("{}", part);
}
// 统计字符数:
let n = s.chars().count();
println!("{} 个字符", n);
// 字节数 len() 不等于字符数

字符串解析

str::parse 解析为数值。parse::<T>() 需标注目标类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
fn main() {
// 解析为 i32:
let n: i32 = "42".parse().unwrap();
// 显式泛型:
let f: f64 = "3.14".parse().unwrap();
let u: u32 = "255".parse().unwrap();
// 错误处理:
let result = "abc".parse::<i32>();
match result {
Ok(v) => println!("{}", v),
Err(e) => println!("解析失败: {}", e),
}
// 布尔:
let b: bool = "true".parse().unwrap();
// 数字转字符串:
let s = 42.to_string();
let s2 = format!("{}", 3.14);
// ? 简化:
// fn f() -> Result<i32, ParseIntError> {
// Ok("42".parse()?)
// }

字符操作

char 方法:大小写、数字判断、空白。字符串方法组合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
fn main() {
let c = 'a';
// 判断:
println!("{}", c.is_alphabetic());
println!("{}", c.is_numeric());
println!("{}", c.is_whitespace());
println!("{}", c.is_ascii());
// 大小写:
let up = 'a'.to_uppercase().to_string();
let low = 'A'.to_lowercase().to_string();
// 字符串方法:
let s = "Hello, Rust!";
s.to_lowercase();
s.to_uppercase();
s.trim(); // 去空白
s.starts_with("Hello");
s.contains("Rust");
s.replace("Rust", "Go");
// 子串:
let sub = &s[7..]; // "Rust!"
// 检查空:s.is_empty()
// 重复:"ab".repeat(3)

字符串方法

查询、修剪、分割、判断。常用 str 方法链式调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
fn main() {
let s = " Hello, Rust 2024 ";
// 修剪与大小写:
let t = s.trim();
let lower = t.to_lowercase();
let upper = t.to_uppercase();
// 查询:
t.starts_with("Hello");
t.ends_with("2024");
t.contains("Rust");
t.find("Rust"); // Option<usize>
// 分割:
let parts: Vec<&str> = t.split(",").collect();
let lines: Vec<&str> = t.lines().collect();
let words: Vec<&str> = t.split_whitespace().collect();
// 替换与删除:
t.replace("Rust", "Go");
t.replacen("o", "0", 1);
// 重复与补全:
"ab".repeat(3);
format!("{:0>5}", 42); // 00042
// 判断空:
s.is_empty();
}

8.集合

Vec、HashMap、集合类型与迭代器。

Vec

Vec<T> 动态数组。可变长,可增删。栈上引用、堆上数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
fn main() {
// 创建:
let mut v = Vec::new();
v.push(1);
v.push(2);
// 宏创建:
let mut v2 = vec![10, 20, 30];
let zero = vec![0; 5]; // [0,0,0,0,0]
// 访问:
let a = &v2[0]; // 索引,越界 panic
let b = v2.get(1); // Option,安全
// 修改:
v2[0] = 99;
v2.push(40);
v2.pop(); // 移除末尾
v2.remove(1); // 移除索引
v2.insert(0, 5); // 插入开头
// 长度:v2.len()
// 清空:v2.clear()
// 遍历:for x in &v2 {}
// 排序:v2.sort()

Vec 操作

迭代、过滤、映射、收集。切片视图与所有权。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
fn main() {
let v = vec![1, 2, 3, 4];
// 迭代器转换:
let doubled: Vec<i32> =
v.iter().map(|x| x * 2).collect();
// 过滤:
let evens: Vec<&i32> =
v.iter().filter(|x| **x % 2 == 0).collect();
// 求和:
let sum: i32 = v.iter().sum();
// 最大值:
let max = v.iter().max();
// 查找:
let found = v.iter().find(|x| **x == 3);
// 遍历修改:
let mut w = vec![1, 2];
for x in w.iter_mut() {
*x += 10;
}
// 移动遍历:
let owned: Vec<i32> = w.into_iter()
.map(|x| x + 1).collect();
// 切片视图:
let part = &v[1..3];

HashMap

HashMap<K, V> 键值对。哈希实现,无序。查找 O(1)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
use std::collections::HashMap;
fn main() {
// 创建:
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Red"), 20);
// 宏创建:
let mut m: HashMap<&str, i32> =
HashMap::from([("a", 1), ("b", 2)]);
// 读取:
let score = scores.get("Blue"); // Option
// 遍历:
for (k, v) in &scores {
println!("{}: {}", k, v);
}
// 插入或更新:
*m.entry("a").or_insert(0) += 10;
m.insert("c", 3);
// 删除:
m.remove("a");
// 检查:
m.contains_key("b");
// 长度:m.len()
// 无序,遍历顺序随机

HashSet

HashSet<T> 唯一元素集合。去重、交集、并集、差集。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
use std::collections::HashSet;
fn main() {
// 创建:
let mut set = HashSet::new();
set.insert(1);
set.insert(2);
set.insert(2); // 重复忽略
println!("{:?}", set); // {1, 2}
// 操作:
set.contains(&1); // true
set.remove(&1);
set.len();
// 集合运算:
let a: HashSet<i32> = [1, 2, 3].into_iter().collect();
let b: HashSet<i32> = [2, 3, 4].into_iter().collect();
// 并集:
let u: HashSet<_> = a.union(&b).cloned().collect();
// 交集:
let i: HashSet<_> = a.intersection(&b).cloned().collect();
// 差集:
let d: HashSet<_> = a.difference(&b).cloned().collect();
// 判断子集:a.is_subset(&b)

BTree

BTreeMap/BTreeSet 有序键。按序遍历。性能略逊哈希。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
use std::collections::BTreeMap;
fn main() {
// 有序键值对:
let mut m = BTreeMap::new();
m.insert("b", 2);
m.insert("a", 1);
m.insert("c", 3);
// 按序遍历:
for (k, v) in &m {
println!("{}: {}", k, v);
} // a b c 有序
// 区间查询:
for (_k, v) in m.range("a".."c") {
println!("{}", v);
}
// 最大/最小:
let first = m.first_key_value();
let last = m.last_key_value();
// BTreeSet 同理念:
use std::collections::BTreeSet;
let s: BTreeSet<i32> = [3, 1, 2].into_iter().collect();
println!("{:?}", s); // {1, 2, 3}
// 适用:
// 需要有序遍历/范围查询
// 键可比较即可

迭代器

Iterator trait 驱动链式操作。惰性求值。消费才执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
fn main() {
let v = vec![1, 2, 3, 4, 5];
// 链式:
let result: Vec<i32> = v.iter()
.filter(|x| **x % 2 == 1) // 奇数
.map(|x| x * 10)
.collect();
println!("{:?}", result); // [10, 30, 50]
// 惰性:不消费不执行
// 常用适配器:
// .take(n) 取前 n
// .skip(n) 跳过 n
// .rev() 反转
// .zip(iter) 配对
// .enumerate() 加索引
// 消费方法:
let sum: i32 = v.iter().sum();
let count = v.iter().count();
let any = v.iter().any(|x| x > 3);
let all = v.iter().all(|x| x > 0);
// 数组转为迭代器:
for x in v.iter() { println!("{}", x); }

VecDeque

VecDeque 双端队列。两端高效增删。环形缓冲。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
use std::collections::VecDeque;
fn main() {
// 创建:
let mut d = VecDeque::new();
// 两端操作:
d.push_back(1);
d.push_back(2);
d.push_front(0);
println!("{:?}", d); // [0, 1, 2]
d.pop_front(); // 0
d.pop_back(); // 2
// 访问:
d.front(); // Option
d.back();
d.front_mut();
// 范围:
d.make_contiguous();
// 适合:
// 队列/先进先出
// 滑动窗口
// 双端扫描
// 与 Vec 区别:
// 前端插入 Vec 是 O(n)
// VecDeque 两端 O(1)
// 随机索引略慢

嵌套集合

集合的组合。Vec<HashMap>、HashMap 嵌套、多维 Vec。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
use std::collections::HashMap;
fn main() {
// Vec 存结构体:
let users = vec![
("a", 1),
("b", 2),
];
// HashMap 嵌套:
let mut matrix: HashMap<String, Vec<i32>> =
HashMap::new();
matrix.insert("row1".to_string(), vec![1, 2]);
// 插入不存在则新建:
matrix.entry(String::from("row2"))
.or_insert(vec![]).push(3);
// 多维 Vec:
let mut grid = vec![vec![0; 3]; 3];
grid[0][1] = 5;
// 结构体集合:
#[derive(Debug)]
struct Item { id: u32, tags: Vec<String> }
let items = vec![
Item { id: 1, tags: vec!["x".into()] },
];
println!("{:?}", items);
}

9.内存与所有权扩展

堆分配、智能指针与共享所有权。

栈与堆

栈上固定大小、快速。堆上动态大小、需分配。所有权管理生命周期。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fn main() {
// 栈上数据:
let x = 42; // 固定大小,栈上
// 堆上数据:
let s = String::from("动态大小");
// String 结构在栈,数据在堆
// 自动管理:
// 离开作用域,栈立即弹
// 堆内存由所有权系统释放
// 无手动 free,无泄漏
// 释放时机:
// 所有者离开作用域(Drop)
// Box/智能指针控制堆对象
// 递归结构需 Box
// 大数组放堆避免栈溢出
}

Box

Box<T> 把值放堆上。大小确定、转移所有权。递归类型必需。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
fn main() {
// 堆上分配:
let b = Box::new(5);
println!("{}", *b); // 解引用
// 递归类型必需 Box:
enum List {
Cons(i32, Box<List>),
Nil,
}
let list = List::Cons(1,
Box::new(List::Cons(2, Box::new(List::Nil))));
// Box 只提供单所有权
// 用途:
// 大结构体减少拷贝
// 动态大小 trait 对象
// 递归数据结构
// 解引用自动:
// b.len() 自动 deref
// 离开作用域自动释放

Rc

Rc<T> 引用计数共享所有权。单线程。多个所有者只读。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
use std::rc::Rc;
fn main() {
// 共享所有权:
let a = Rc::new(String::from("shared"));
let b = Rc::clone(&a); // 引用计数 +1
let c = Rc::clone(&a);
println!("{}", a);
println!("{}", b);
// 计数:
println!("{}", Rc::strong_count(&a)); // 3
// 只读共享:
// Rc 中的数据不可变
// 需要可变用 RefCell
// 单线程专用:
// 多线程用 Arc
// 循环引用导致泄漏:
// 用 Weak 打破
// 离开作用域计数减一

RefCell

RefCell<T> 运行时借用检查。内部可变性。借用冲突 panic。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
use std::cell::RefCell;
fn main() {
// 内部可变性:
let cell = RefCell::new(42);
*cell.borrow_mut() += 1; // 修改
println!("{}", cell.borrow());
// 运行时借用规则:
// 一个可变借用 或
// 多个不可变借用
// 冲突:
// let b1 = cell.borrow();
// let b2 = cell.borrow_mut(); // panic!
// 用途:
// 结构体内可变字段
// 配合 Rc 共享可变
// 与 &mut 区别:
// 编译期 -> 运行时
// 绕开借用检查器
// 需谨慎,保持借用范围短

Arc

Arc<T> 线程安全引用计数。多线程共享所有权。原子计数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
use std::sync::Arc;
use std::thread;
fn main() {
// 线程安全共享:
let data = Arc::new(vec![1, 2, 3]);
let mut handles = vec![];
for i in 0..3 {
let d = Arc::clone(&data);
handles.push(thread::spawn(move || {
println!("线程 {}: {:?}", i, d);
}));
}
for h in handles {
h.join().unwrap();
}
// 与 Rc 区别:
// Arc 用原子计数,线程安全
// Rc 单线程
// 只读共享:
// 可变需 Mutex 配合:
// Arc<Mutex<T>>
// 注意避免循环引用

Mutex

Mutex<T> 互斥访问内部值。锁保护。与 Arc 组合共享可变。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
// 共享可变状态:
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let c = Arc::clone(&counter);
handles.push(thread::spawn(move || {
let mut num = c.lock().unwrap();
*num += 1; // 加锁修改
}));
}
for h in handles {
h.join().unwrap();
}
println!("{}", *counter.lock().unwrap());
// 锁生命周期:
// lock() 返回 Guard
// 离开作用域自动解锁
// 中毒:
// 持锁 panic 后锁中毒
// unwrap 处理 or_else
// 多锁注意死锁顺序

原子类型

AtomicU32 等原子操作。无锁并发计数。Ordering 内存序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
use std::sync::atomic::{
AtomicU32, Ordering
};
use std::thread;
fn main() {
// 原子计数器:
let counter = AtomicU32::new(0);
let mut handles = vec![];
for _ in 0..10 {
let c = &counter;
handles.push(thread::spawn(move || {
c.fetch_add(1, Ordering::SeqCst);
}));
}
for h in handles {
h.join().unwrap();
}
println!("{}", counter.load(Ordering::SeqCst));
// 类型:
// AtomicU8..AtomicI64
// AtomicBool AtomicUsize
// 操作:
// fetch_add / fetch_sub
// compare_exchange
// load / store
// 内存序:
// Relaxed/Release/Acquire
// SeqCst 最严格
// 无锁、不阻塞

智能指针

Deref/Drop trait。Box/Rc/Arc 实现。指针抽象与自动清理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
use std::ops::Deref;
// 自定义智能指针:
struct MyBox<T>(T);
// Deref 允许解引用:
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
// Drop 释放清理:
impl<T> Drop for MyBox<T> {
fn drop(&mut self) {
println!("释放");
}
}
fn main() {
let m = MyBox(5);
println!("{}", *m); // 解引用 5
// 离开作用域自动 drop
// 标准智能指针:
// Box<T> 堆分配
// Rc<T> 单线程共享
// Arc<T> 多线程共享
// RefCell/Mutex 内部可变
// String/Vec 也是指针+容量

10.trait 与泛型

trait 抽象、实现、泛型约束与多态。

trait 定义

trait 定义共享行为。方法签名。类似接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 定义 trait:
#[derive(Debug)]
struct Dog;
struct Cat;
// 行为抽象:
trait Speak {
fn sound(&self) -> &'static str;
}
// 为类型实现:
impl Speak for Dog {
fn sound(&self) -> &'static str {
"汪汪"
}
}
impl Speak for Cat {
fn sound(&self) -> &'static str {
"喵"
}
}
fn main() {
let dog = Dog;
let cat = Cat;
println!("{}", dog.sound());
println!("{}", cat.sound());
}
// trait 可含默认实现
// 实现必须满足方法签名
// 同一类型可实现多 trait

实现 trait

impl Trait for Type 实现行为。孤儿规则:trait 或类型必须本地。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 为内置类型实现自定义 trait:
trait Greeting {
fn hello(&self) -> String;
}
// 为 &str 实现:
impl Greeting for &str {
fn hello(&self) -> String {
format!("你好,{}", self)
}
}
// 为 Vec 实现:
impl Greeting for Vec<i32> {
fn hello(&self) -> String {
format!("{:?} 长度 {}", self, self.len())
}
}
fn main() {
println!("{}", "Nick".hello());
println!("{}", vec![1, 2].hello());
}
// 孤儿规则:
// trait 或 类型 至少一个本地
// 否则编译错误
// 空实现:
// 标记类型(sealed)
// 泛型实现可复用

默认方法

trait 方法可提供默认实现。覆盖可选。调用顺序自动。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
trait Animal {
fn name(&self) -> String;
// 默认实现:
fn intro(&self) -> String {
format!("我是 {}", self.name())
}
}
struct Dog;
impl Animal for Dog {
fn name(&self) -> String {
"小狗".to_string()
}
// 可选覆盖:
fn intro(&self) -> String {
format!("{} 汪汪", self.name())
}
}
struct Cat;
impl Animal for Cat {
fn name(&self) -> String {
"小猫".to_string()
}
// 用默认 intro
}
fn main() {
println!("{}", Dog.intro()); // 小狗 汪汪
println!("{}", Cat.intro()); // 我是 小猫
}
// 默认方法可调用 trait 其他方法

trait 对象

dyn Trait 动态分派。异构集合。运行时多态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
trait Draw {
fn draw(&self);
}
struct Circle;
struct Square;
impl Draw for Circle {
fn draw(&self) {
println!("画圆");
}
}
impl Draw for Square {
fn draw(&self) {
println!("画方");
}
}
// 动态分派:
fn draw_all(shapes: &[&dyn Draw]) {
for s in shapes {
s.draw();
}
}
// 装箱 trait 对象:
fn make() -> Box<dyn Draw> {
Box::new(Circle)
}
fn main() {
let shapes: Vec<&dyn Draw> =
vec![&Circle, &Square];
draw_all(&shapes);
// 运行时决定调用哪个实现
// dyn 有运行时开销
// 静态分派用泛型更快
// 对象安全限制
}

泛型

泛型类型与函数。T 抽象。代码复用。单态化零开销。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 泛型函数:
fn identity<T>(x: T) -> T {
x
}
// 泛型结构体:
struct Point<T> {
x: T,
y: T,
}
// 多个类型参数:
struct Pair<A, B> {
first: A,
second: B,
}
// 泛型方法:
impl<T> Point<T> {
fn x(&self) -> &T {
&self.x
}
}
fn main() {
let p = Point { x: 1, y: 2 }; // 推断 i32
println!("{}", p.x());
let ip = Point { x: 1.5, y: 2.5 };
println!("{}", ip.x());
// 单态化:
// 编译期生成具体版本
// 无运行时开销
// 与 dyn 对比更高效

泛型约束

T: Trait 约束。where 从句。约束 trait 组合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 基本约束:
fn print_it<T: std::fmt::Debug>(x: &T) {
println!("{:?}", x);
}
// where 从句:
fn complex<T, U>(a: &T, b: &U)
where
T: std::fmt::Display + Clone,
U: std::fmt::Debug,
{
println!("{}", a);
println!("{:?}", b);
}
// 返回泛型:
fn pair() -> impl std::fmt::Display {
42 // 不透明返回类型
}
// trait 约束泛型集合:
fn sortable<T: Ord>(list: &mut [T]) {
list.sort();
}
// 约束使泛型方法可用
// impl Trait 参数简写
// 多约束用 + 组合

impl 块

impl 关联方法与关联函数。self、Self。构造函数约定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
// 关联函数(无 self):
fn new(w: u32, h: u32) -> Rectangle {
Rectangle { width: w, height: h }
}
// 方法(&self):
fn area(&self) -> u32 {
self.width * self.height
}
// 可变方法(&mut self):
fn set_width(&mut self, w: u32) {
self.width = w;
}
// 消耗 self:
fn into_string(self) -> String {
format!("{}x{}", self.width, self.height)
}
}
fn main() {
let mut r = Rectangle::new(2, 3);
println!("{}", r.area());
r.set_width(5);
// Self 类型在 impl 内引用自身
// 多 impl 块可分开定义
}

组合与多态

Rust 无继承。用 trait + 组合复用。默认实现替代基类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 组合替代继承:
struct Engine {
power: u32,
}
impl Engine {
fn start(&self) {
println!("引擎启动 {} 马力", self.power);
}
}
struct Car {
engine: Engine, // 组合
model: String,
}
impl Car {
fn start(&self) {
self.engine.start(); // 委托
println!("{} 发车", self.model);
}
}
// trait 默认方法做基类效果:
trait Fly {
fn fly(&self) {
println!("飞行");
}
}
struct Bird;
impl Fly for Bird {} // 用默认
// 多态:
fn make_fly(f: &dyn Fly) {
f.fly();
}
fn main() {
let car = Car {
engine: Engine { power: 150 },
model: String::from("Guru"),
};
car.start();
}
// 组合更灵活、无菱形继承问题

11.错误处理

Result、Option、? 运算符、panic 与自定义错误。

Result

Result<T, E> 返回成功值或错误。Ok/Err 变体。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
use std::fs::File;
fn main() {
// Result 枚举:
let result = File::open("nope.txt");
// match 处理:
match result {
Ok(file) => println!("打开成功"),
Err(e) => println!("打开失败: {}", e),
}
// 泛型签名:
// enum Result<T, E> {
// Ok(T),
// Err(E),
// }
// 手动构造:
let ok: Result<i32, String> = Ok(42);
let err: Result<i32, String> =
Err(String::from("失败"));
// 方法:
let v = ok.unwrap_or(0);
let v2 = ok.unwrap_or_else(|_| -1);
}

unwrap 与 expect

unwrap 成功取值,失败 panic。expect 带自定义消息。调试用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
fn main() {
let ok: Result<i32, &str> = Ok(10);
// unwrap:
let v = ok.unwrap();
println!("{}", v);
// 失败时 panic:
// let e: Result<i32, &str> = Err("bad");
// e.unwrap(); // panic!
// expect 带消息:
// let e = Err("bad");
// e.expect("应该成功"); // panic 消息
// 适合场景:
// 原型/示例/测试
// 逻辑上不可能失败
// 生产建议:
// 用 ? 传播
// 或 match 处理
// unwrap_or 提供默认值

? 运算符

? 简化错误传播。Err 自动返回,Ok 解包继续。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
use std::fs::File;
use std::io::Read;
// 传播错误:
fn read_file(path: &str) -> Result<String, std::io::Error> {
let mut f = File::open(path)?; // Err 直接返回
let mut s = String::new();
f.read_to_string(&mut s)?;
Ok(s)
}
// 链式:
fn first_line(path: &str) -> Result<String, std::io::Error> {
let content = read_file(path)?;
Ok(content.lines().next().unwrap_or("").to_string())
}
// ? 自动转换错误:
// 需要 From 实现
// fn f() -> Result<(), Box<dyn Error>> {
// File::open("x")?; // io::Error 自动装箱
// Ok(())
// }
// 函数必须返回 Result/Option

实现 Error

标准 Error trait。Display + Debug 打印。错误链。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
use std::error::Error;
use std::fmt;
// 自定义错误类型:
#[derive(Debug)]
struct MyError {
msg: String,
}
// Display:
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "发生错误: {}", self.msg)
}
}
// 实现 Error:
impl Error for MyError {}
fn main() {
let e = MyError { msg: "xxx".to_string() };
println!("{}", e); // Display
println!("{:?}", e); // Debug
println!("{}", e.source()); // 无来源
}
// Error trait 要求 Display + Debug
// source() 返回底层错误
// 用于 ? 和错误链

自定义错误

设计自己的错误类型。枚举变体携带上下文。错误分类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#[derive(Debug)]
// 分类错误:
enum AppError {
NotFound(String),
InvalidInput { field: String, reason: String },
Io(std::io::Error),
}
// 手动实现 Display:
impl std::fmt::Display for AppError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
AppError::NotFound(msg) =>
write!(f, "未找到: {}", msg),
AppError::InvalidInput { field, reason } =>
write!(f, "{} 无效: {}", field, reason),
AppError::Io(e) => write!(f, "IO: {}", e),
}
}
}
impl std::error::Error for AppError {}
// 转换:
impl From<std::io::Error> for AppError {
fn from(e: std::io::Error) -> AppError {
AppError::Io(e)
}
}
// 使用:
// fn f() -> Result<(), AppError> {
// std::fs::read_to_string("x")?; // 自动转换
// Ok(())
// }

thiserror

thiserror 派生宏自动实现 Display/Error。减少样板代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Cargo.toml 添加:
// thiserror = "2"
use thiserror::Error;
// 派生宏:
#[derive(Error, Debug)]
// 错误枚举:
#[derive(Error, Debug)]
enum DataError {
#[error("记录不存在: {0}")]
NotFound(String),
#[error("校验失败: {field} {reason}")]
Validation {
field: String,
reason: String,
},
#[error(transparent)]
Io(#[from] std::io::Error),
}
// 自动获得:
// Display 实现
// Error 实现
// From<std::io::Error> 转换
fn main() {
let e = DataError::NotFound("id".into());
println!("{}", e);
}
// 大幅减少手写样板
// 生态标准做法

Option

Option<T> 处理可能缺失。Some/None。安全访问。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
fn main() {
// Option 类型:
let some = Some(5);
let none: Option<i32> = None;
// match:
match some {
Some(v) => println!("值 {}", v),
None => println!("无值"),
}
// 常用方法:
let x = some.unwrap_or(0);
let y = some.unwrap_or_else(|| compute());
let z = none.unwrap_or(0); // 0
// 链式:
let doubled = some.map(|v| v * 2);
let filtered = some.filter(|v| v > 3);
let flat = Some(Some(1)).flatten();
// 组合:
let a = Some(1);
let b = Some(2);
let sum = a.zip(b).map(|(x, y)| x + y);
// 常见:
// Vec::get / HashMap::get
// 用 ? 传播 None

panic

panic! 不可恢复错误。程序崩溃并展开栈。仅用于bug。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
fn main() {
// 触发 panic:
// panic!("致命错误");
// 索引越界:
let v = vec![1, 2, 3];
// let x = v[10]; // panic!
// 空 slice 取首:
let empty: &[i32] = &[];
// let x = empty[0]; // panic!
// panic 行为:
// 打印错误信息
// 展开栈,运行 Drop
// 程序终止
// 自定义消息:
// panic!("索引 {} 越界", 10);
// 适用场景:
// 程序无法继续的 bug
// 契约被破坏
// 可恢复用 Result
}

12.输入输出

标准输入输出、文件读写与文件系统。

读取输入

stdin 读取一行。read_line 到 String。trim 去除换行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
use std::io;
fn main() {
// 读取一行:
let mut input = String::new();
io::stdin().read_line(&mut input)
.expect("读取失败");
// 去除换行符:
let trimmed = input.trim();
println!("你输入了: {}", trimmed);
// 读取数字:
let mut line = String::new();
io::stdin().read_line(&mut line).unwrap();
let n: i32 = line.trim().parse().unwrap();
println!("数字: {}", n);
// 循环读取:
loop {
let mut s = String::new();
let bytes = io::stdin().read_line(&mut s).unwrap();
if bytes == 0 { break; } // EOF
print!("{}", s);
}
}

读取文件

read_to_string 一次性读入。Read trait 流式读取。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
use std::fs;
fn main() {
// 一次性读取为字符串:
let content = fs::read_to_string("data.txt")
.expect("读取失败");
println!("{}", content);
// 读取为字节:
let bytes = fs::read("data.bin").unwrap();
// 流式读取(大文件):
use std::io::{Read, BufReader};
let f = fs::File::open("big.log").unwrap();
let mut reader = BufReader::new(f);
let mut buf = String::new();
reader.read_to_string(&mut buf).unwrap();
// 逐行读取:
use std::io::BufRead;
let f = fs::File::open("data.txt").unwrap();
for line in std::io::BufReader::new(f).lines() {
println!("{}", line.unwrap());
}
}

写入文件

write/append 写入。OpenOptions 控制模式。缓冲写入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
use std::fs;
fn main() {
// 覆盖写入:
fs::write("out.txt", "hello\n")
.expect("写入失败");
// 追加写入:
use std::fs::OpenOptions;
use std::io::Write;
let mut f = OpenOptions::new()
.append(true)
.create(true)
.open("log.txt")
.unwrap();
f.write_all(b"more data\n").unwrap();
// 缓冲写入:
let mut writer = std::io::BufWriter::new(
fs::File::create("buf.txt").unwrap());
writeln!(writer, "第 {} 行", 1).unwrap();
writer.flush().unwrap(); // 刷入磁盘
// 格式写入:
// write!(f, "{}", value)
}

文件系统

创建目录、删除、重命名、判断存在。路径操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
use std::fs;
fn main() {
// 创建目录:
fs::create_dir("data").unwrap();
fs::create_dir_all("data/a/b").unwrap();
// 删除:
fs::remove_file("tmp.txt").unwrap();
fs::remove_dir("data/a").unwrap();
fs::remove_dir_all("data").unwrap();
// 重命名:
fs::rename("a.txt", "b.txt").unwrap();
// 判断存在:
if fs::metadata("b.txt").is_ok() {
println!("存在");
}
// 元数据:
let meta = fs::metadata("b.txt").unwrap();
println!("大小: {}", meta.len());
println!("目录: {}", meta.is_dir());
// 复制:
fs::copy("b.txt", "c.txt").unwrap();
}

BufRead 逐行

BufRead trait 逐行读取。lines()、read_line、split。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
use std::io::BufRead;
use std::io::BufReader;
use std::fs::File;
fn main() {
let f = File::open("data.txt").unwrap();
let reader = BufReader::new(f);
// 逐行:
for line in reader.lines() {
let l = line.unwrap();
println!("{}", l);
}
// 带行号:
let f = File::open("data.txt").unwrap();
for (i, line) in
BufReader::new(f).lines().enumerate() {
println!("{}: {}", i + 1, line.unwrap());
}
// 手动读取一行:
// let mut buf = String::new();
// reader.read_line(&mut buf)
// 分割字节:
// for part in reader.split(b",") {}
// 从 stdin 也可以用
}

输出与写入

print!/println!/eprintln!。write!/writeln! 到任意写入者。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
use std::io::{self, Write};
fn main() {
// 标准输出:
println!("普通输出");
print!("无换行");
// 标准错误:
eprintln!("错误信息");
// 写入 Vec:
let mut buf = Vec::new();
writeln!(buf, "写入 Vec {}", 1).unwrap();
println!("{:?}", buf);
// 写入 String:
let mut s = String::new();
write!(s, "格式化 {}", 42).unwrap();
println!("{}", s);
// 写入文件(见文件节)
// io::stdout() 也可用:
// let mut out = io::stdout();
// writeln!(out, "直接写 stdout")
// Flush 手动刷新
}

标准流

stdin/stdout/stderr 标准流。交互与管道数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
use std::io::{self, Read, Write};
fn main() {
// 管道读取全部:
// echo data | program
let mut buf = String::new();
io::stdin().read_to_string(&mut buf).unwrap();
// 逐行处理管道:
// for line in io::stdin().lines() {
// println!("{} ", line.unwrap());
// }
// 输出到 stdout:
println!("处理完成");
// 错误到 stderr:
eprintln!("警告: 非致命");
// 写入 stdout:
// io::stdout().write_all(b"raw\n")
// 交互提示:
// print!("输入名字: ");
// io::stdout().flush().unwrap();
}

字节读取

read 读字节到缓冲。流式处理二进制。write_all 写全部。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
use std::fs::File;
use std::io::{self, Read, Write};
fn main() {
// 读取到缓冲:
let mut f = File::open("data.bin").unwrap();
let mut buf = [0u8; 1024];
let n = f.read(&mut buf).unwrap();
println!("读取 {} 字节", n);
// 循环读取直到 EOF:
let mut f = File::open("data.bin").unwrap();
let mut total = 0;
let mut buf = [0u8; 256];
loop {
let n = f.read(&mut buf).unwrap();
if n == 0 { break; } // EOF
total += n;
// 处理 buf[..n]
}
// 写入全部:
let mut out = File::create("out.bin").unwrap();
out.write_all(&[1, 2, 3, 4]).unwrap();
// 读取全部字节:
let all = std::fs::read("data.bin").unwrap();
println!("总 {} 字节", all.len());
}

13.常见误区

Rust 新手最容易踩的坑与正确写法。

移动后使用

值被移动后不能使用。借用或 clone 保留所有权。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// BAD:移动后访问
fn main() {
let s = String::from("hi");
let t = s; // 移动
// println!("{}", s); // 错误:已移动
println!("{}", t);
}
// GOOD:借用
fn main() {
let s = String::from("hi");
let t = &s; // 借用
println!("{} {}", s, t);
}
// GOOD:显式克隆
let s = String::from("hi");
let t = s.clone();
// 场景:
// 函数传值转移所有权
// 需要两处使用
// 借用更高效,clone 更直接

借用冲突

不可变借用与可变借用不能并存。作用域缩短借用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// BAD:同时借用
fn main() {
let mut v = vec![1, 2, 3];
// let r1 = &v; // 不可变
// v.push(4); // 可变,冲突
// println!("{:?}", r1);
}
// GOOD:先结束不可变借用
fn main() {
let mut v = vec![1, 2, 3];
let r1 = &v[0];
println!("{}", r1); // 借用结束
v.push(4); // 现在允许
}
// GOOD:分开作用域
{
let r = &v;
println!("{:?}", r);
} // 借用结束
v.push(4);
// 规则:
// 读读可以,读写不行
// 编译器保证无数据竞争

悬垂引用

返回局部变量的引用会悬垂。返回拥有所有权或生命周期。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// BAD:返回局部引用
// fn bad() -> &String {
// let s = String::from("x");
// &s // 错误:s 被释放
// }
// GOOD:返回所有权
fn good() -> String {
String::from("x")
}
// GOOD:引用输入
fn first_char(s: &str) -> &str {
&s[..1]
}
// GOOD:生命周期参数
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
// 规则:
// 返回的引用必须有效
// 指向堆或参数的生命周期
// 编译器(借用检查器)拦截

String 拼接

+ 拼接会移动左侧。重复拼接性能差。用 format! 或 push_str。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// BAD:重复 + 拼接
let mut s = String::new();
// for _ in 0..10 {
// s = s + "x"; // 每次重新分配
// }
// GOOD:push_str 追加
let mut s = String::new();
for _ in 0..10 {
s.push_str("x");
}
// GOOD:format! 一次性
let a = "hello";
let b = "world";
let s = format!("{}, {}", a, b);
// + 语法:
let s1 = String::from("a");
let s2 = String::from("b");
let s3 = s1 + &s2; // s1 被移动
// 原因:
// + 需要 String 左操作数
// 大量拼接扩容频繁
// format!/join 更优

索引类型

索引与长度是 usize,不能直接是 i32。集合索引类型不匹配。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// BAD:i32 索引
fn main() {
let v = vec![1, 2, 3];
let i: i32 = 1;
// let x = v[i]; // 错误:usize 需要
// let x = v[i as usize]; // 转换
}
// GOOD:直接 usize
fn main() {
let v = vec![1, 2, 3];
let i: usize = 1;
let x = v[i]; // 正确
println!("{}", x);
}
// 场景:
// for (i, x) in v.iter().enumerate()
// 返回的是 usize
// len() 也是 usize
// 计算距离类型不匹配时:
// 用 as usize 转换
// 或调整变量类型

match 分支类型

match 所有分支返回类型必须一致。缺分支需 _ 通配。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// BAD:分支类型不一致
// let x = match 5 {
// 1 => "one",
// _ => 42, // 错误:str vs i32
// };
// GOOD:统一返回类型
let x = match 5 {
1 => "one",
_ => "other", // 都是 &str
};
// BAD:不穷尽
// enum Color { R, G, B }
// let c = Color::R;
// match c {
// Color::R => {}
// Color::G => {}
// // 缺 B,编译错误
// }
// GOOD:加通配
// match c {
// Color::R => {}
// _ => {}
// }
// 规则:
// 穷尽性编译期检查
// 类型推断按首个分支

闭包捕获

闭包自动按需借用或移动。同时借用冲突。move 显式转移。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// BAD:闭包借用与修改冲突
fn main() {
let mut count = 0;
// let print = || println!("{}", count);
// count += 1; // 冲突:已被借用
// print();
}
// GOOD:先结束闭包
fn main() {
let mut count = 0;
{
let print = || println!("{}", count);
print();
} // 借用结束
count += 1;
}
// GOOD:move 闭包
let data = vec![1, 2];
let handler = move || {
println!("{:?}", data); // 拥有所有权
};
// 规则:
// Fn / FnMut / FnOnce
// 按捕获方式自动选择
// 线程传闭包需 move
// 冲突时缩小借用范围

整数溢出

调试构建溢出 panic。发布构建回绕。显式处理或选类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// BAD:调试构建溢出 panic
// fn main() {
// let x: u8 = 255;
// let y = x + 1; // 调试 panic!
// }
// GOOD:显式检查
fn main() {
let x: u8 = 255;
match x.checked_add(1) {
Some(v) => println!("{}", v),
None => println!("溢出"),
}
// 其他方法:
// x.checked_add / checked_mul
// x.wrapping_add // 回绕
// x.saturating_add // 饱和到上限
// x.overflowing_add // 返回进位
// 发布构建默认回绕
// 大计数用 u64/usize
// 明确语义选对方法

14.并发

线程、channel、共享状态与 Send/Sync。

线程

thread::spawn 启动新线程。join 等待完成。返回值可传递。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
use std::thread;
use std::time::Duration;
fn main() {
// 启动线程:
let handle = thread::spawn(|| {
for i in 1..3 {
println!("子线程 {}", i);
thread::sleep(Duration::from_millis(10));
}
});
// 主线程继续:
for i in 1..3 {
println!("主线程 {}", i);
}
// 等待子线程结束:
handle.join().unwrap();
// join 可获取返回值:
let h = thread::spawn(|| 42);
let result = h.join().unwrap();
println!("{}", result); // 42
}

move 闭包

move 闭包把捕获值移入线程。避免借用悬垂。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
use std::thread;
fn main() {
let data = String::from("hello");
// 线程借用 data:
let h1 = thread::spawn(move || {
println!("{} 世界", data);
});
// data 已移动,主线程不能再用
// 需要多线程共享:
// 用 Arc(见共享节)
// 循环中 move:
let mut handles = vec![];
for i in 0..3 {
handles.push(thread::spawn(move || {
println!("线程 {}", i);
}));
}
for h in handles {
h.join().unwrap();
}
// 无 move 闭包:
// 捕获引用,可能借用主线程
// 线程可能比借用活得更久
// move 明确转移所有权

channel

mpsc 多生产者单消费者。send/recv 传输数据。类型安全。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
use std::sync::mpsc;
use std::thread;
fn main() {
// 创建通道:
let (tx, rx) = mpsc::channel();
// 发送端移动到子线程:
thread::spawn(move || {
tx.send(String::from("hello")).unwrap();
});
// 接收:
let received = rx.recv().unwrap();
println!("收到: {}", received);
// recv 阻塞等待
// 无值发送者全 Drop 时 recv 报错
// try_recv 非阻塞:
// match rx.try_recv() {
// Ok(v) => ...,
// Err(_) => println!("暂无数据"),
// }
// 迭代接收:
// for v in rx {
// println!("{}", v);
// }

多生产者

Sender 克隆实现多生产者。共享一个接收端。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
use std::sync::mpsc;
use std::thread;
fn main() {
let (tx, rx) = mpsc::channel();
// 克隆发送端:
let tx1 = tx.clone();
let tx2 = tx.clone();
// 三个生产者:
thread::spawn(move || {
tx.send(1).unwrap();
});
thread::spawn(move || {
tx1.send(2).unwrap();
});
thread::spawn(move || {
tx2.send(3).unwrap();
});
// 主线程消费:
for _ in 0..3 {
let v = rx.recv().unwrap();
println!("收到 {}", v);
}
// 接收顺序不保证
// 单消费者:
// mpsc 只允许一个 rx
// 多消费者需拆分或互斥
// 通道是消息传递首选
// 避免共享可变状态

共享可变

Arc<Mutex<T>> 多线程共享可变数据。锁保护读写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
// 共享计数器:
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
handles.push(thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1; // 临界区
}));
}
for h in handles {
h.join().unwrap();
}
println!("结果: {}", *counter.lock().unwrap());
// Mutex 保证互斥
// Arc 保证引用计数线程安全
// 锁 Guard 离开作用域释放
// 持锁时间尽量短
// 避免锁中调用会再取锁
// 死锁风险注意顺序

scoped 线程

thread::scope 借用非 'static 数据。无需 move 所有权。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
use std::thread;
fn main() {
let mut data = vec![1, 2, 3];
// 借用作用域内数据:
thread::scope(|s| {
// 不可变借用:
s.spawn(|| {
println!("{:?}", data);
});
// 可变借用(分线程):
s.spawn(|| {
data.push(4); // 仅此线程用
});
}); // 作用域结束,全部线程完成
println!("{:?}", data);
// 与 thread::spawn 区别:
// spawn 要求 'static 所有权
// scope 可借用局部变量
// scope 结束时自动 join
// 适用:并行处理局部数据
}

rayon 并行

rayon 并行迭代器。par_iter 替代 iter。数据并行简单化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Cargo.toml:
// rayon = "1"
use rayon::prelude::*;
fn main() {
let v: Vec<i32> = (0..1000).collect();
// 并行求和:
let sum: i32 = v.par_iter().sum();
println!("{}", sum);
// 并行映射:
let doubled: Vec<i32> =
v.par_iter().map(|x| x * 2).collect();
// 并行过滤:
let evens: Vec<&i32> =
v.par_iter().filter(|x| **x % 2 == 0).collect();
// 并行排序:
let mut sorted = vec![3, 1, 2];
sorted.par_sort();
// 数据必须 Send
// 自动分块并行
// 大集合收益明显
// 小集合开销更大
// 结果与串行一致

Send 与 Sync

Send 可跨线程移动。Sync 可被引用共享。安全并发保障。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Send:所有权可跨线程
// 绝大多数类型是 Send
// 例外:Rc<T> 不是 Send
// Sync:可被 &T 共享
// 例外:RefCell 不是 Sync
use std::rc::Rc;
use std::thread;
fn main() {
// Rc 不能进线程:
// let rc = Rc::new(5);
// thread::spawn(move || println!("{}", rc));
// 错误:Rc 不是 Send
// 用 Arc 替代:
let arc = std::sync::Arc::new(5);
let h = thread::spawn(move || println!("{}", arc));
h.join().unwrap();
// 规则:
// Send 类型可跨线程
// Sync 类型可安全共享引用
// 编译器检查跨线程使用
// 自定义类型自动派生
// unsafe impl 需谨慎

15.网络

TCP、UDP、HTTP 与第三方网络库。

TCP 连接

TcpStream 建立连接。read/write 收发数据。流式协议。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
use std::net::TcpStream;
use std::io::{Read, Write};
fn main() {
// 建立连接:
let mut stream = TcpStream::connect(
"example.com:80").unwrap();
// 发送 HTTP 请求:
stream.write_all(
b"GET / HTTP/1.0\r\nHost: example.com\r\n\r\n")
.unwrap();
// 读取响应:
let mut buf = [0u8; 4096];
let n = stream.read(&mut buf).unwrap();
println!("{}", String::from_utf8_lossy(&buf[..n]));
// 连接错误处理:
// TcpStream::connect 返回 Result
// 设置超时:
// stream.set_read_timeout(Some(Duration::from_secs(5)))
// 双向流式通信
}

TCP 监听

TcpListener 绑定监听端口。accept 接受连接。多连接线程处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
use std::net::{TcpListener, TcpStream};
use std::io::{Read, Write};
use std::thread;
fn main() {
// 绑定端口:
let listener = TcpListener::bind("127.0.0.1:8080")
.unwrap();
println!("监听 8080");
// 接受连接:
for stream in listener.incoming() {
match stream {
Ok(stream) => {
// 每连接一线程:
thread::spawn(|| handle(stream));
}
Err(e) => eprintln!("连接错误: {}", e),
}
}
}
fn handle(mut stream: TcpStream) {
let mut buf = [0u8; 1024];
let n = stream.read(&mut buf).unwrap();
println!("收到 {} 字节", n);
stream.write_all(&buf[..n]).unwrap();
}

HTTP 请求

reqwest 发起 HTTP 请求。JSON 请求与响应。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Cargo.toml:
// reqwest = { version = "0.12", features = ["json"] }
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// GET 请求:
let resp = reqwest::Client::new()
.get("https://api.example.com/users")
.timeout(Duration::from_secs(10))
.send()
.await?;
// 状态码:
println!("状态: {}", resp.status());
// 读取文本:
let body = resp.text().await?;
println!("{}", &body[..200]);
Ok(())
}
// 需 tokio 运行时:
// tokio = { version = "1", features = ["full"] }
// JSON:
// .json::<T>() 反序列化
// serde 配合

HTTP 服务

axum 构建 HTTP 服务。路由与处理器。异步。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Cargo.toml:
// axum = "0.7"
// tokio = { version = "1", features = ["full"] }
// serde_json = "1"
use axum::{Router, routing::get};
use axum::response::Json;
use serde_json::{json, Value};
#[tokio::main]
async fn main() {
// 路由:
let app = Router::new()
.route("/", get(root))
.route("/api/ping", get(ping));
// 启动:
let listener = tokio::net::TcpListener::bind(
"127.0.0.1:3000").await.unwrap();
println!("服务运行在 3000");
axum::serve(listener, app).await.unwrap();
}
async fn root() -> &'static str {
"Hello, GuruToolkit!"
}
async fn ping() -> Json<Value> {
Json(json!({ "ok": true }))
}
// 路由参数:
// .route("/user/{id}", get(user_by_id))

URL 处理

url crate 解析与构建 URL。查询参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// Cargo.toml:
// url = "2"
use url::Url;
fn main() {
// 解析:
let url = Url::parse(
"https://[email protected]/path?q=rust#sec")
.unwrap();
// 访问字段:
println!("{}", url.scheme()); // https
println!("{}", url.host_str().unwrap());
println!("{}", url.path());
println!("{}", url.fragment().unwrap());
// 查询参数:
let pairs: Vec<(String, String)> =
url.query_pairs().into_owned().collect();
for (k, v) in pairs {
println!("{}={}", k, v);
}
// 构建 URL:
let mut u = Url::parse("https://api.com").unwrap();
u.set_path("/v1/users");
u.query_pairs_mut()
.append_pair("page", "2");
println!("{}", u);
}

IP 解析

std::net::IpAddr 解析 IP。判断 IPv4/IPv6。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
fn main() {
// 解析 IP:
let ip: IpAddr = "192.168.1.1".parse().unwrap();
println!("{}", ip);
// 判断版本:
match ip {
IpAddr::V4(v) => println!("IPv4: {}", v),
IpAddr::V6(v) => println!("IPv6: {}", v),
}
// 构造:
let v4 = Ipv4Addr::new(127, 0, 0, 1);
let v6: Ipv6Addr = "::1".parse().unwrap();
// 属性:
println!("回环: {}", v4.is_loopback());
println!("私有: {}", v4.is_private());
// 端口组合:
let addr = "127.0.0.1:8080".parse::<std::net::SocketAddr>().unwrap();
println!("{}", addr.port());
// 域名解析:
// use std::net::ToSocketAddrs;
// let mut it = "example.com:80".to_socket_addrs().unwrap();
}

UDP

UdpSocket 无连接数据报。send_to/recv_from。无需握手。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
use std::net::UdpSocket;
fn main() {
// 绑定本地:
let socket = UdpSocket::bind("127.0.0.1:0")
.unwrap();
// 发送数据报:
socket.send_to(b"hello", "127.0.0.1:9999")
.unwrap();
// 接收:
let mut buf = [0u8; 1024];
let (n, src) = socket.recv_from(&mut buf).unwrap();
println!("来自 {}: {}", src,
String::from_utf8_lossy(&buf[..n]));
// 服务端:
let server = UdpSocket::bind("127.0.0.1:9999")
.unwrap();
// 特点:
// 无连接、无握手
// 可能丢包乱序
// 效率高于 TCP
// 适合:DNS、视频、游戏
// 可靠传输自行实现
}

DNS 解析

ToSocketAddrs 解析域名。查地址列表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
use std::net::ToSocketAddrs;
fn main() {
// 域名解析:
let addrs = "example.com:80"
.to_socket_addrs().unwrap();
for addr in addrs {
println!("{}", addr);
}
// 端口默认:
let addrs = "example.com"
.to_socket_addrs().unwrap();
// 解析可能返回多个地址
// 依次尝试连接
// 错误处理:
match "bad-domain.invalid:80".to_socket_addrs() {
Ok(it) => println!("解析成功"),
Err(e) => println!("解析失败: {}", e),
}
// 异步 DNS:
// 第三方库 tokio::net
// 生产用 resolv-conf
// 测试用本地 hosts

16.时间与日期

SystemTime、Instant、Duration 与 chrono。

SystemTime

SystemTime 系统时钟。获取当前时间。与 UNIX 纪元比较。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
use std::time::SystemTime;
fn main() {
// 当前时间:
let now = SystemTime::now();
// UNIX 纪元:
let epoch = SystemTime::UNIX_EPOCH;
// 距纪元:
match now.duration_since(epoch) {
Ok(d) => println!("距纪元 {:?}", d),
Err(e) => println!("系统时间早于纪元: {:?}", e),
}
// 比较:
let later = SystemTime::now();
let elapsed = later.duration_since(now).unwrap();
println!("经过 {:?}", elapsed);
// 限制:
// 不精确(系统时钟可能调)
// 测耗时用 Instant
// 日期处理用 chrono
// 时间戳:
let secs = now.duration_since(epoch)
.unwrap().as_secs();
println!("{} 秒", secs);
}

Instant 计时

Instant 单调时钟测量耗时。不受系统时间调整影响。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
use std::time::Instant;
fn main() {
// 开始计时:
let start = Instant::now();
// 执行耗时操作:
std::thread::sleep(std::time::Duration::from_millis(50));
// 计算耗时:
let elapsed = start.elapsed();
println!("耗时: {:?}", elapsed);
// 不同单位:
println!("{} 微秒", elapsed.as_micros());
println!("{} 毫秒", elapsed.as_millis());
// 多个起点比较:
let a = Instant::now();
let b = Instant::now();
let diff = b.duration_since(a);
// 使用场景:
// 性能基准、超时控制
// 单调递增、不受时钟影响
// 不能跨进程比较
}

Duration

Duration 时间段。秒/纳秒精度。算术与转换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
use std::time::Duration;
fn main() {
// 创建:
let sec = Duration::from_secs(5);
let ms = Duration::from_millis(1500);
let us = Duration::from_micros(100);
let ns = Duration::from_nanos(1);
// 组合:
let d = Duration::new(2, 500_000_000); // 2.5s
// 算术:
let sum = sec + ms;
let mul = sec * 2;
// 比较:
let a = Duration::from_secs(1);
let b = Duration::from_millis(500);
println!("{} > {}", a > b, a > b);
// 转换:
println!("{} 秒", sec.as_secs());
println!("{} 毫秒", ms.as_millis());
// 用途:
// sleep、超时、等待
// 网络超时配置
}

chrono 当前时间

chrono crate 处理日期时间。Utc/Local 时区。人类可读。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Cargo.toml:
// chrono = "0.4"
use chrono::{Utc, Local, NaiveDate};
fn main() {
// UTC 时间:
let utc = Utc::now();
println!("{}", utc);
// 本地时间:
let local = Local::now();
println!("{}", local);
// 访问字段:
println!("年: {}", utc.year());
println!("月: {}", utc.month());
println!("日: {}", utc.day());
println!("时: {}", utc.hour());
println!("星期: {}", utc.weekday());
// 时间戳:
println!("{}", utc.timestamp());
// 日期构造:
let d = NaiveDate::from_ymd_opt(2026, 8, 2)
.unwrap();
println!("{}", d);
// 时区标记:
// +00:00 UTC / +08:00 中国
}

格式化输出

format 格式化日期。strftime 风格占位符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// chrono = "0.4"
use chrono::Utc;
fn main() {
let now = Utc::now();
// 格式化:
println!("{}", now.format("%Y-%m-%d")); // 2026-08-02
println!("{}", now.format("%H:%M:%S")); // 14:30:22
println!("{}", now.format("%Y-%m-%d %H:%M"));
// 常用占位符:
// %Y 年 %m 月 %d 日
// %H 时 %M 分 %S 秒
// %A 星期全名 %a 缩写
// %B 月份全名
// %j 年中第几天
// 自定义:
println!("{}", now.format("%Y/%m/%d %H:%M:%S %z"));
// 默认 Display:
println!("{}", now);
// 返回 String:
let s = now.format("%F").to_string();
println!("{}", s); // ISO 日期
}

解析字符串

DateTime::parse_from_str 解析。ISO 8601 解析。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// chrono = "0.4"
use chrono::{DateTime, NaiveDateTime, Utc};
fn main() {
// 解析固定格式:
let dt = DateTime::parse_from_str(
"2026-08-02 10:30:00 +0800",
"%Y-%m-%d %H:%M:%S %z").unwrap();
println!("{}", dt);
// ISO 8601:
let iso = DateTime::parse_from_rfc3339(
"2026-08-02T10:30:00+08:00").unwrap();
println!("{}", iso);
// 无时区解析:
let naive = NaiveDateTime::parse_from_str(
"2026-08-02 10:30:00",
"%Y-%m-%d %H:%M:%S").unwrap();
println!("{}", naive);
// 转 UTC:
let utc: DateTime<Utc> = iso.with_timezone(&Utc);
println!("{}", utc);
// 解析失败返回 Err
}

时间运算

加减时间、计算间隔、时间范围判断。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// chrono = "0.4"
use chrono::{Duration, Utc, Local};
fn main() {
let now = Utc::now();
// 加减:
let tomorrow = now + Duration::days(1);
let next_hour = now + Duration::hours(1);
let last_week = now - Duration::weeks(1);
println!("{}", tomorrow.format("%F"));
// 间隔:
let later = now + Duration::minutes(90);
let diff = later - now;
println!("间隔 {} 分钟", diff.num_minutes());
// 日期范围判断:
let start = now - Duration::hours(1);
let end = now + Duration::hours(1);
let now_local = Local::now();
let n = now_local.with_timezone(&Utc);
if n >= start && n <= end {
println!("在范围内");
}
// 时区:
// FixedOffset::east_opt(8 * 3600)
// 中国时区 +08:00
}

时区处理

FixedOffset 固定时区。本地时区偏移。跨时区转换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// chrono = "0.4"
use chrono::{Utc, Local, FixedOffset, TimeZone};
fn main() {
// 固定时区(中国 +08:00):
let cst = FixedOffset::east_opt(8 * 3600).unwrap();
let now = Utc::now();
let beijing = now.with_timezone(&cst);
println!("北京: {}", beijing);
// 本地时区:
let local = Local::now();
println!("本地: {}", local);
// 转换回 UTC:
let utc = beijing.with_timezone(&Utc);
println!("UTC: {}", utc);
// 任意时区:
let tokyo = FixedOffset::east_opt(9 * 3600).unwrap();
let tokyo_now = now.with_timezone(&tokyo);
println!("东京: {}", tokyo_now);
// 偏移量:
println!("偏移: {}", cst); // +08:00
// 存数据建议存 UTC
// 显示时再转时区
}

17.进程与环境

命令行参数、环境变量、子进程与路径。

参数与环境

std::env 读取参数与环境变量。args 与 var。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
use std::env;
fn main() {
// 命令行参数:
let args: Vec<String> = env::args().collect();
println!("{:?}", args);
// 第一个是程序路径
// 环境变量:
match env::var("PATH") {
Ok(v) => println!("PATH: {}", v),
Err(e) => println!("未设置: {:?}", e),
}
// 带默认值:
let port = env::var("PORT")
.unwrap_or_else(|_| "8080".to_string());
// 判断存在:
// env::var_os("KEY").is_some()
// 设置环境变量:
// env::set_var("KEY", "value")
// 遍历全部:
// for (k, v) in env::vars() {}
}

clap 参数解析

clap 解析命令行参数。子命令、选项、帮助。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Cargo.toml:
// clap = { version = "4", features = ["derive"] }
use clap::Parser;
// 定义参数:
#[derive(Parser, Debug)]
#[command(name = "app", version, about)]
struct Args {
/// 用户名
#[arg(short, long)]
name: String,
/// 次数
#[arg(short, long, default_value_t = 1)]
count: u32,
/// 详细输出
#[arg(short, long)]
verbose: bool,
}
fn main() {
let args = Args::parse();
println!("{:?}", args);
for _ in 0..args.count {
println!("你好 {}", args.name);
}
}
// 运行:
// app --name Nick --count 3 -v
// 自动生成帮助:--help
// 参数校验自动完成

std::process

退出码、Command 子进程、当前进程信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
use std::process;
fn main() {
// 退出码:
// process::exit(0) 成功
// process::exit(1) 失败
// 当前进程 ID:
println!("PID: {}", process::id());
// 运行子进程:
let out = process::Command::new("ls")
.arg("-l")
.output()
.expect("运行失败");
println!("状态: {}", out.status);
println!("输出: {}",
String::from_utf8_lossy(&out.stdout));
// 检查是否成功:
if out.status.success() {
println!("命令成功");
}
// 等待完成:
// process::Command::new("x").status()
}

Command 子进程

Command 控制子进程。参数、环境、管道、输出捕获。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
use std::process::Command;
use std::io::Write;
fn main() {
// 带参数运行:
let mut cmd = Command::new("echo");
cmd.arg("hello").arg("world");
let output = cmd.output().unwrap();
println!("{}",
String::from_utf8_lossy(&output.stdout));
// 管道输入:
let mut child = Command::new("cat")
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped())
.spawn().unwrap();
child.stdin.as_mut().unwrap()
.write_all(b"data").unwrap();
// 设置环境变量:
let out = Command::new("sh")
.arg("-c")
.arg("echo $MYVAR")
.env("MYVAR", "hello")
.output().unwrap();
println!("{}",
String::from_utf8_lossy(&out.stdout));
}

PathBuf

Path/PathBuf 路径操作。拼接、组件、规范化。跨平台。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
use std::path::{Path, PathBuf};
fn main() {
// 创建:
let mut p = PathBuf::from("/tmp");
p.push("data");
p.push("file.txt");
println!("{}", p.display());
// 组件:
println!("父: {:?}", p.parent());
println!("名: {:?}", p.file_name());
println!("扩展名: {:?}", p.extension());
// 判断:
println!("绝对: {}", p.is_absolute());
println!("存在: {}", p.exists());
// 规范化:
let messy = Path::new("./a/../b");
let clean = messy.canonicalize();
// 拼接字符串:
let joined = Path::new("/data")
.join(format!("{}.log", 2026));
println!("{}", joined.display());
// 与 &str 互转:
let s = p.to_string_lossy();
}

工作目录

当前目录、切换目录、用户目录。路径相关操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
use std::env;
fn main() {
// 当前目录:
let cwd = env::current_dir().unwrap();
println!("{}", cwd.display());
// 切换目录:
// env::set_current_dir("/tmp").unwrap();
// 用户主目录:
let home = env::home_dir();
match home {
Some(h) => println!("主目录: {}", h.display()),
None => println!("无主目录"),
}
// 临时目录:
let tmp = env::temp_dir();
println!("临时: {}", tmp.display());
// 可执行路径:
let exe = env::current_exe().unwrap();
println!("程序: {}", exe.display());
// 相对路径组合:
let config = env::current_dir().unwrap()
.join("config")
.join("app.toml");
}

目录遍历

read_dir 遍历目录。递归收集文件。过滤类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
use std::fs;
fn main() {
// 读取目录:
let entries = fs::read_dir(".").unwrap();
for entry in entries {
let e = entry.unwrap();
let path = e.path();
// 类型判断:
if path.is_dir() {
println!("[目录] {}", path.display());
} else {
println!("[文件] {}", path.display());
}
}
// 收集文件名:
let files: Vec<String> = fs::read_dir("src")
.unwrap()
.filter_map(|e| e.ok())
.filter(|e| e.path().is_file())
.map(|e| e.file_name().to_string_lossy()
.into_owned())
.collect();
println!("{:?}", files);
// 递归需自己实现或用 walkdir
}

信号处理

ctrlc crate 捕获 Ctrl+C。优雅退出。清理资源。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Cargo.toml:
// ctrlc = "3"
use std::sync::atomic::{
AtomicBool, Ordering
};
use std::sync::Arc;
fn main() {
// 捕获 Ctrl+C:
let running = Arc::new(AtomicBool::new(true));
let r = Arc::clone(&running);
ctrlc::set_handler(move || {
println!("\n收到中断,退出中...");
r.store(false, Ordering::SeqCst);
}).expect("设置信号处理失败");
// 主循环:
while running.load(Ordering::SeqCst) {
// 处理任务...
std::thread::sleep(
std::time::Duration::from_millis(100));
}
println!("清理完成,再见");
}
// 用途:
// 保存状态、关闭连接
// 优雅关闭服务
// 标准库:
// 信号原生处理需 libc/unsafe

18.正则表达式

regex crate 匹配、捕获、替换与分割。

编译正则

Regex::new 编译。r#... 原始字符串。编译昂贵需复用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Cargo.toml:
// regex = "1"
use regex::Regex;
fn main() {
// 编译:
let re = Regex::new(r"^[a-z]+$").unwrap();
// 原始字符串 r"..." 避免转义
// 返回 Result,非法模式报错
// 编译较慢,复用:
// 用 lazy_static/OnceLock 缓存
// 或线程局部
// 常用模式:
let email = Regex::new(
r"^[\w.+-]+@[\w-]+\.[\w.]+$").unwrap();
println!("{}", email.is_match("[email protected]"));
// 错误:
match Regex::new(r"[") {
Ok(_) => {}
Err(e) => println!("正则错误: {}", e),
}
}

匹配判断

is_match 判断是否匹配。部分匹配。整串匹配需锚点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
use regex::Regex;
fn main() {
let re = Regex::new(r"\d+").unwrap();
// 是否包含匹配:
println!("{}", re.is_match("abc123")); // true
// 部分匹配默认:
// 只判断是否出现
// 整串匹配:
let full = Regex::new(r"^\d+$").unwrap();
println!("{}", full.is_match("123")); // true
println!("{}", full.is_match("123a")); // false
// find 获取位置:
let m = re.find("abc123").unwrap();
println!("位置 {}..{}", m.start(), m.end());
// 大小写:
let case = Regex::new(r"(?i)rust").unwrap();
println!("{}", case.is_match("RUST"));
}

捕获分组

捕获组提取子串。captures 返回分组。命名组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
use regex::Regex;
fn main() {
// 捕获组:
let re = Regex::new(r"(\d{4})-(\d{2})-(\d{2})")
.unwrap();
let caps = re.captures("日期 2026-08-02").unwrap();
// caps[0] 整个匹配:
println!("{}", &caps[0]); // 2026-08-02
// caps[1..] 各分组:
println!("年: {}", &caps[1]);
println!("月: {}", &caps[2]);
println!("日: {}", &caps[3]);
// 命名组:
let named = Regex::new(r"(?P<year>\d{4})")
.unwrap();
let caps = named.captures("2026").unwrap();
println!("年: {}", caps.name("year").unwrap().as_str());
// 匹配不到返回 None
// 多组迭代:
// captures_iter 全部匹配

全部匹配

find_iter 遍历所有匹配。captures_iter 全部带分组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
use regex::Regex;
fn main() {
let re = Regex::new(r"\d+").unwrap();
let text = "a1 b22 c333";
// 所有匹配:
let nums: Vec<&str> =
re.find_iter(text).map(|m| m.as_str()).collect();
println!("{:?}", nums); // ["1", "22", "333"]
// 迭代位置:
for m in re.find_iter(text) {
println!("{} 在 {}..{}", m.as_str(), m.start(), m.end());
}
// 分组全部:
let pair = Regex::new(r"(\w+)=(\w+)").unwrap();
for caps in pair.captures_iter("a=1 b=2") {
println!("{} = {}", &caps[1], &caps[2]);
}
// 无匹配返回空迭代器
}

替换

replace 替换匹配。$1 引用分组。replace_all 全部替换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
use regex::Regex;
fn main() {
let re = Regex::new(r"\d+").unwrap();
// 替换所有:
let out = re.replace_all("a1 b2", "#");
println!("{}", out); // a# b#
// 只替换第一个:
let first = re.replace("a1 b2", "#");
println!("{}", first); // a# b2
// 分组引用:
let name = Regex::new(r"(\w+),\s*(\w+)").unwrap();
let out = name.replace_all("Doe, John", "$2 $1");
println!("{}", out); // John Doe
// 回调替换:
let out = re.replace_all("a1 b2", |caps: &regex::Captures| {
let n: i32 = caps[0].parse().unwrap();
format!("{}", n * 2)
});
println!("{}", out); // a2 b4
}

分割

split 按正则分割字符串。splitn 限制数量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
use regex::Regex;
fn main() {
// 按分隔符分割:
let re = Regex::new(r"[,;]+").unwrap();
let parts: Vec<&str> =
re.split("a,b;c,,d").collect();
println!("{:?}", parts); // ["a", "b", "c", "d"]
// 按空白分割:
let ws = Regex::new(r"\s+").unwrap();
let words: Vec<&str> =
ws.split("hello world").collect();
println!("{:?}", words);
// 限制数量:
let parts2: Vec<&str> = re.splitn("a,b,c", 2).collect();
println!("{:?}", parts2); // ["a", "b,c"]
// 保留匹配分隔符:
// let parts: Vec<&str> =
// re.split_inclusive("a,b", 0).collect();
// 简单分割用 str::split 更快
// 复杂模式才用 regex

常见模式

常用正则写法。邮箱、URL、手机号、IP。字符类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
use regex::Regex;
fn main() {
// 邮箱:
let email = Regex::new(
r"^[\w.+-]+@[\w-]+\.[\w.]+$").unwrap();
println!("{}", email.is_match("[email protected]"));
// URL:
let url = Regex::new(r"^https?://[\w.-]+(/\S*)?$").unwrap();
println!("{}", url.is_match("https://example.com"));
// 手机号(中国):
let phone = Regex::new(r"^1[3-9]\d{9}$").unwrap();
println!("{}", phone.is_match("13800138000"));
// 字符类:
// \d 数字 \w 单词 \s 空白
// \D \W \S 反义
// + 一次以上 * 零次以上
// {2,4} 次数 {2,} 至少两次
// ^ 开头 $ 结尾
// [a-z] [^0-9] 字符范围
// 贪婪 ? 变非贪婪:\d+?
// 分组 ( ) 或 |
}

标志与大小写

(?i) 忽略大小写等内联标志。RegexBuilder 配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
use regex::Regex;
fn main() {
// 忽略大小写:
let re = Regex::new(r"(?i)rust").unwrap();
println!("{}", re.is_match("RUST"));
println!("{}", re.is_match("rust"));
// 多行模式:
// (?m) ^ $ 匹配每行
let m = Regex::new(r"(?m)^go").unwrap();
println!("{}", m.is_match("x\ngo"));
// 点匹配换行:
// (?s) . 匹配 \n
// 无内联:
// RegexBuilder 可配置
let re = regex::RegexBuilder::new("rust")
.case_insensitive(true)
.multi_line(true)
.build().unwrap();
println!("{}", re.is_match("RUST"));
// 单行:
// .size_limit() 限制复杂度
// 默认 UTF-8,禁用用 bytes
}

19.构建与测试

cargo 构建、单元测试、lint 与发布配置。

cargo build

构建项目。调试/发布模式。产物位置。增量编译。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 调试构建:
// cargo build
// 发布构建(优化):
// cargo build --release
// 检查(不生成二进制):
// cargo check
// 产物:
// target/debug/ target/release/
// 指定包:
// cargo build -p mylib
// 增量编译:
// 未变文件不重编译
// 功能选择:
// cargo build --features xxx
// 清理:
// cargo clean
// 运行:
// cargo run
// 直接运行二进制:
// ./target/debug/app
// 构建选项在 Cargo.toml [profile]

单元测试

#[test] 属性。cargo test 运行。断言宏。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 单元测试:
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(add(1, 2), 3);
}
#[test]
fn test_sub() {
assert!(sub(2, 1) == 1);
}
#[test]
#[should_panic] // 期望 panic
fn test_bad() {
panic!("boom");
}
}
fn add(a: i32, b: i32) -> i32 { a + b }
fn sub(a: i32, b: i32) -> i32 { a - b }
// 运行:
// cargo test
// 运行单个:
// cargo test test_add
// 显示输出:
// cargo test -- --nocapture
// 断言宏:
// assert_eq! / assert_ne!
// assert! 带消息

文档测试

/// 文档注释可运行。cargo test 验证示例。集成测试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/// 两数相加。
///
/// # 示例
/// ```
/// let result = add(1, 2);
/// assert_eq!(result, 3);
/// ```
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
// 文档测试:
// 示例代码会被编译运行
// cargo test 验证
// 生成文档:
// cargo doc --open
// 集成测试:
// tests/integration.rs
// 直接调用公共 API
// 运行:cargo test
// 文档注释语法:
// /// 文档注释
// //! 模块级文档
// ```rust,ignore 跳过
// ```text 不编译

依赖管理

Cargo.toml 声明依赖。版本语义。cargo update。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Cargo.toml 依赖:
// [dependencies]
// serde = "1" // 兼容任意 1.x
// serde = "1.0.100" // 精确下限
// serde = "=1.0.100" // 精确版本
// serde = "^1.2" // 兼容
// 可选依赖:
// [dependencies]
// serde = { version = "1", optional = true }
// 开发依赖:
// [dev-dependencies]
// pretty_assertions = "1"
// 更新:
// cargo update // 更新锁文件
// cargo add serde // 添加依赖
// cargo remove serde // 移除
// 检查过期:
// cargo outdated
// 审计漏洞:
// cargo audit

clippy 检查

cargo clippy 代码检查。发现潜在 bug 与风格问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 运行检查:
// cargo clippy
// 严格模式:
// cargo clippy -- -D warnings
// 常见检查:
// 1. 不必要的克隆
// 2. 可简化写法
// 3. 性能陷阱
// 4. 可疑逻辑
// 示例问题:
// let v = vec![1, 2];
// if v.len() > 0 {} // clippy 建议
// if !v.is_empty() {} // 更好
// 忽略规则:
// #[allow(clippy::all)]
// 局部允许:
// #[allow(clippy::redundant_clone)]
// 配置文件:
// clippy.toml
// 集成 CI 常用 -D warnings
// 用 & 代替 .iter() 等建议

代码格式化

cargo fmt 统一格式。rustfmt。团队一致风格。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 格式化:
// cargo fmt
// 检查格式(不修改):
// cargo fmt --check
// 配置文件:
// rustfmt.toml
// 常用配置:
// max_width = 100
// tab_spaces = 4
// 特性:
// 自动缩进对齐
// 导入排序(需 nightly):
// cargo +nightly fmt
// CI 检查:
// cargo fmt --check
// 与 clippy 配合:
// 先 fmt 再 clippy
// 编辑器保存时自动
// 团队统一风格
// 减少 diff 冲突

发布配置

[profile.release] 优化配置。裁剪二进制、LTO。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Cargo.toml:
// [profile.release]
// opt-level = 3 // 优化级别
// lto = true // 链接时优化
// codegen-units = 1 // 单代码单元
// panic = "abort" // 直接终止
// strip = "symbols" // 去符号
// debug = false // 无调试信息
// 小体积组合:
// [profile.release]
// lto = true
// strip = "symbols"
// opt-level = "z" // 偏大小
// 构建:
// cargo build --release
// 查看大小:
// ls -lh target/release/app
// 发布前:
// cargo fmt --check
// cargo clippy -- -D warnings
// cargo test
// 版本号:
// Cargo.toml version 字段

文档生成

cargo doc 生成 API 文档。rustdoc 标记。发布前跑文档测试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 生成文档:
// cargo doc
// 打开浏览器:
// cargo doc --open
// 文档注释:
/// 计算两个数的和。
///
/// # 参数
/// - `a`:第一个数
/// - `b`:第二个数
///
/// # 返回
/// 和
///
/// # 示例
/// ```
/// assert_eq!(add(1, 2), 3);
/// ```
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
// 文档常用标记:
// # Examples # Panics
// # Errors # Safety
// 模块文档://!
// 内链:\[`add`\]
// 私有项不生成
// 发布前跑 doc 测试

官方链接

直达官方文档与资源。

关于本速查

本页是 Rust 2021 版的自包含速查手册,覆盖语言核心与最常用 std API 在真实项目中约 80% 的常见用法。内容偏向现代惯用法:? 传播错误、match 穷尽匹配、用迭代器替代手写循环、严格区分 String 与 &str。权威参考见 Rust 官方 Book 与标准库文档。 19 个章节各自聚焦一个主题——从第一个程序到所有权、trait、并发与常见误区。每节拆成 8 个带示例的小节(每个 5–20 行),共约 150 个主题。代码片段刻意短小、自解释。 所有处理都在浏览器中完成——无上传、无追踪。本页是 GuruToolkit 免费开发者工具集的一部分;代码片段可自由使用,无任何担保。

版本 2.1.0