Rust
Rust 是一门系统级编程语言,专注于内存安全、并发安全和高性能。它在编译期通过所有权(Ownership)系统消除内存错误和数据竞争,无需垃圾回收器,性能与 C/C++ 相当,是 WebAssembly、嵌入式、操作系统、高性能服务等场景的首选语言。
核心特性:
| 特性 | 说明 |
|---|---|
| 所有权(Ownership) | 每个值有且只有一个所有者,离开作用域自动释放,无需 GC |
| 借用(Borrowing) | 通过引用访问数据,编译期检查引用有效性,防止悬垂指针 |
| 生命周期(Lifetime) | 编译器追踪引用的存活范围,确保引用永不比数据活得更长 |
| 零成本抽象 | 泛型、trait、迭代器等高级特性编译后无运行时开销 |
| 无数据竞争 | 借用规则保证同一时刻只有一个可变引用或多个不可变引用 |
| 模式匹配 | 穷举性 match 表达式,配合 enum 处理所有情况 |
| Cargo | 官方包管理器 + 构建系统,集成测试、文档、发布 |
安装
# 通过 rustup 安装(官方推荐)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# 安装后刷新环境
source $HOME/.cargo/env
# 验证安装
rustc --version
cargo --version
rustup --version
# 更新到最新稳定版
rustup update
# 安装 nightly(部分实验特性需要)
rustup toolchain install nightly
rustup default nightly # 切换为默认
rustup default stable # 切回稳定版
# 添加编译目标(交叉编译)
rustup target add wasm32-unknown-unknown # WebAssembly
rustup target add aarch64-unknown-linux-gnu # ARM64 Linux
推荐工具
# rust-analyzer(LSP,IDE 智能提示)
rustup component add rust-analyzer
# rustfmt(代码格式化)
rustup component add rustfmt
cargo fmt
# clippy(代码检查/lint)
rustup component add clippy
cargo clippy
# cargo-watch(文件变化自动重编译)
cargo install cargo-watch
cargo watch -x run
# cargo-expand(展开宏)
cargo install cargo-expand
cargo expand
# cargo-audit(安全漏洞检查)
cargo install cargo-audit
cargo audit
Cargo 项目管理
# 创建新项目
cargo new hello_world # 二进制项目(bin)
cargo new my_lib --lib # 库项目(lib)
# 项目结构
# hello_world/
# ├── Cargo.toml # 包元数据 + 依赖声明
# ├── Cargo.lock # 依赖版本锁文件(bin 项目提交,lib 项目不提交)
# └── src/
# └── main.rs # 入口(bin)/ lib.rs(lib)
# 构建与运行
cargo build # Debug 构建(target/debug/)
cargo build --release # Release 构建(target/release/),开启优化
cargo run # 构建并运行
cargo run -- arg1 arg2 # 传递命令行参数
cargo check # 只检查语法,不生成产物(比 build 快)
# 测试
cargo test # 运行所有测试
cargo test test_name # 运行名称包含关键字的测试
cargo test -- --nocapture # 显示 println! 输出
# 文档
cargo doc --open # 生成并打开文档
# 依赖管理
cargo add serde # 添加依赖
cargo add serde --features derive
cargo add tokio --features full
cargo remove serde # 移除依赖
cargo update # 更新所有依赖到兼容的最新版
Cargo.toml
[package]
name = "my_app"
version = "0.1.0"
edition = "2021" # Rust Edition,目前最新是 2021
[dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tokio = { version = "1", features = ["full"] }
anyhow = "1"
thiserror = "1"
clap = { version = "4", features = ["derive"] }
reqwest = { version = "0.12", features = ["json"] }
[dev-dependencies] # 只在测试时使用
mockall = "0.13"
[build-dependencies] # 构建脚本依赖
cc = "1"
[profile.release]
opt-level = 3 # 最高优化
lto = true # 链接时优化
codegen-units = 1 # 减少并行代码生成(更慢但更小)
strip = true # 去除符号表
[profile.dev]
opt-level = 0 # 不优化,加快编译速度
基础语法
变量与数据类型
fn main() {
// 变量默认不可变
let x = 5;
// x = 6; // 编译错误
// mut 使变量可变
let mut y = 5;
y = 6;
// 常量(必须标注类型,编译期求值)
const MAX_POINTS: u32 = 100_000;
// 遮蔽(Shadowing):同名新变量覆盖旧变量
let x = x + 1; // x = 6
let x = x * 2; // x = 12
let x = "hello"; // 可以改变类型
// 解构赋值
let (a, b, c) = (1, 2, 3);
let [first, .., last] = [1, 2, 3, 4, 5];
}
标量类型:
// 整数
let a: i8 = -128; // 有符号 8 位
let b: u8 = 255; // 无符号 8 位
let c: i32 = 2_147_483_647; // 有符号 32 位(默认整数类型)
let d: i64 = 9_223_372_036_854_775_807;
let e: u64 = 18_446_744_073_709_551_615;
let f: isize = -1; // 指针大小(平台相关)
let g: usize = 42; // 索引/长度常用
// 进制字面量
let hex = 0xFF;
let octal = 0o77;
let bin = 0b1111_0000;
let byte = b'A'; // u8 字节
// 浮点数
let h: f32 = 3.14; // 32 位浮点
let i: f64 = 2.718_281_828; // 64 位浮点(默认)
// 布尔
let j: bool = true;
// 字符(Unicode 标量,4 字节)
let k: char = '中';
let l: char = '😀';
复合类型:
// 元组(固定长度,各元素类型可不同)
let tup: (i32, f64, bool) = (500, 6.4, true);
let (x, y, z) = tup; // 解构
println!("{}", tup.0); // 索引访问
// 数组(固定长度,元素类型相同)
let arr: [i32; 5] = [1, 2, 3, 4, 5];
let zeros = [0; 5]; // [0, 0, 0, 0, 0]
println!("{}", arr[0]);
// 切片(对连续内存的引用,不拥有数据)
let slice: &[i32] = &arr[1..3]; // &[2, 3]
函数
// 基本函数
fn add(x: i32, y: i32) -> i32 {
x + y // 最后一个表达式作为返回值(不加分号)
}
// 多返回值(元组)
fn min_max(arr: &[i32]) -> (i32, i32) {
let min = *arr.iter().min().unwrap();
let max = *arr.iter().max().unwrap();
(min, max)
}
// 发散函数(永不返回)
fn crash(msg: &str) -> ! {
panic!("{}", msg);
}
// 闭包(匿名函数,捕获环境)
let factor = 3;
let multiply = |x: i32| x * factor; // 捕获 factor
println!("{}", multiply(5)); // 15
// 闭包作为参数
fn apply<F: Fn(i32) -> i32>(f: F, x: i32) -> i32 {
f(x)
}
// 高阶函数
let numbers = vec![1, 2, 3, 4, 5];
let sum: i32 = numbers.iter()
.filter(|&&x| x % 2 == 0)
.map(|&x| x * x)
.sum(); // 4 + 16 = 20
控制流
// if 表达式(有返回值)
let number = 7;
let description = if number % 2 == 0 { "偶数" } else { "奇数" };
// loop(无限循环,可返回值)
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2; // break 携带返回值
}
};
// while
while counter < 10 {
counter += 1;
}
// for(迭代器)
for i in 0..5 { // 0, 1, 2, 3, 4
println!("{i}");
}
for i in 0..=5 { // 0, 1, 2, 3, 4, 5(包含右边界)
println!("{i}");
}
for (i, val) in arr.iter().enumerate() {
println!("{i}: {val}");
}
// match 表达式(穷举匹配)
let x = 5;
match x {
1 => println!("一"),
2 | 3 => println!("二或三"),
4..=6 => println!("四到六"),
n if n > 6 => println!("大于六:{n}"),
_ => println!("其他"),
}
// if let(匹配单个模式,简化 match)
if let Some(value) = some_option {
println!("{value}");
}
// while let
while let Some(top) = stack.pop() {
println!("{top}");
}
所有权系统
Rust 最核心的特性,通过三条规则在编译期管理内存:
- 每个值有且只有一个所有者(变量)
- 所有者离开作用域,值被自动释放(调用
drop) - 任意时刻,要么只有一个可变引用,要么有任意多个不可变引用
移动(Move)
// 堆上数据:赋值 = 移动所有权
let s1 = String::from("hello");
let s2 = s1; // s1 的所有权移动到 s2
// println!("{s1}"); // 编译错误:s1 已失效
// 栈上数据(实现了 Copy trait):赋值 = 拷贝
let x = 5;
let y = x; // x 和 y 都有效
println!("{x} {y}"); // 正常
// 实现了 Copy 的类型:所有整数、浮点、bool、char、元组(元素都是 Copy)
// 函数调用也是移动
fn takes_ownership(s: String) { /* s 被移动进来 */ }
let s = String::from("hello");
takes_ownership(s);
// println!("{s}"); // 编译错误
// 函数返回可以把所有权移出
fn gives_ownership() -> String {
String::from("hello") // 移动到调用方
}
借用(Borrowing)
// 不可变引用(&T):可以同时存在多个
let s = String::from("hello");
let len = calculate_length(&s); // 借用,不移动
println!("{s}"); // s 仍然有效
fn calculate_length(s: &String) -> usize {
s.len()
}
// 可变引用(&mut T):同一时刻只能有一个
let mut s = String::from("hello");
let r = &mut s;
r.push_str(", world");
// let r2 = &mut s; // 编译错误:已有一个可变引用
// 不可变引用和可变引用不能同时存在
let mut s = String::from("hello");
let r1 = &s;
let r2 = &s;
// let r3 = &mut s; // 编译错误
println!("{r1} {r2}");
// r1 r2 最后一次使用后,可变引用可以创建
let r3 = &mut s; // ✅
生命周期(Lifetime)
// 生命周期标注:告诉编译器引用间的关系
// 'a 是生命周期参数名(约定用小写字母)
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
// 返回引用的生命周期 ≤ x 和 y 中较短的那个
}
// 结构体中的引用必须标注生命周期
struct Excerpt<'a> {
part: &'a str, // Excerpt 不能比 part 引用的数据活得更长
}
// 静态生命周期:整个程序运行期间有效
let s: &'static str = "I have a static lifetime.";
字符串
Rust 有两种字符串类型,初学者容易混淆:
| 类型 | 存储 | 可变性 | 说明 |
|---|---|---|---|
&str |
栈(指针+长度) | 不可变 | 字符串切片,借用的视图 |
String |
堆 | 可变 | 拥有所有权的字符串 |
// &str:字符串字面量,编译期确定
let s1: &str = "hello";
// String:运行时创建
let s2 = String::from("hello");
let s3 = "hello".to_string();
let s4 = "hello".to_owned();
// 字符串拼接
let s5 = s2 + &s3; // s2 所有权被移动,s3 被借用
let s6 = format!("{s1} world"); // 不移动所有权
// 常用操作
let s = String::from("Hello, 世界!");
println!("{}", s.len()); // 字节长度(非字符数!)
println!("{}", s.chars().count()); // 字符数(正确方式)
println!("{}", s.contains("世界")); // true
println!("{}", s.replace("世界", "World"));
println!("{}", s.to_uppercase());
println!("{}", s.trim());
// 切片(按字节索引,中文字符占 3 字节,需小心)
let hello = &s[0..5]; // "Hello"
// 按字符遍历(正确方式)
for c in s.chars() {
print!("{c} ");
}
// 按字节遍历
for b in s.bytes() {
print!("{b} ");
}
// 字符串转数字
let n: i32 = "42".parse().unwrap();
let n: i32 = "42".parse::<i32>().unwrap();
// 数字转字符串
let s = 42.to_string();
let s = format!("{}", 42);
// 分割与收集
let csv = "a,b,c,d";
let parts: Vec<&str> = csv.split(',').collect();
let joined = parts.join(" | "); // "a | b | c | d"
集合类型
Vec(动态数组)
// 创建
let mut v: Vec<i32> = Vec::new();
let mut v = vec![1, 2, 3, 4, 5];
// 增删
v.push(6);
v.pop(); // 返回 Option<i32>
v.insert(2, 99); // 在索引 2 处插入
v.remove(2); // 删除索引 2 的元素
v.retain(|&x| x % 2 == 0); // 只保留偶数
// 访问
let third = v[2]; // 越界会 panic
let third = v.get(2); // 返回 Option<&i32>,推荐
let first = v.first(); // Option<&i32>
let last = v.last(); // Option<&i32>
// 切片
let slice = &v[1..3]; // &[i32]
// 迭代
for val in &v { } // 不可变迭代
for val in &mut v { *val *= 2; } // 可变迭代
for val in v { } // 消费迭代(v 移动)
// 常用方法
v.len()
v.is_empty()
v.contains(&3)
v.sort() // 原地排序
v.sort_by(|a, b| b.cmp(a)) // 逆序
v.sort_by_key(|x| x.abs()) // 按绝对值排序
v.dedup() // 去除连续重复元素(排序后使用效果好)
v.reverse()
v.extend([7, 8, 9])
v.truncate(3) // 只保留前 3 个
v.clear()
// 函数式操作
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 product: i32 = v.iter().product();
let max = v.iter().max();
let min = v.iter().min();
// 枚举(同时获取索引和值)
let indexed: Vec<(usize, &i32)> = v.iter().enumerate().collect();
// 扁平化
let nested = vec![vec![1, 2], vec![3, 4]];
let flat: Vec<i32> = nested.into_iter().flatten().collect();
HashMap
use std::collections::HashMap;
// 创建
let mut scores: HashMap<String, i32> = HashMap::new();
// 插入
scores.insert(String::from("Alice"), 100);
scores.insert(String::from("Bob"), 80);
// 从迭代器构建
let map: HashMap<&str, i32> = vec![("a", 1), ("b", 2)].into_iter().collect();
// 访问
let score = scores.get("Alice"); // Option<&i32>
let score = scores["Alice"]; // &i32,键不存在会 panic
// 条件插入(键不存在时才插入)
scores.entry(String::from("Charlie")).or_insert(60);
// 基于旧值更新
let text = "hello world hello rust";
let mut word_count: HashMap<&str, i32> = HashMap::new();
for word in text.split_whitespace() {
let count = word_count.entry(word).or_insert(0);
*count += 1;
}
// 删除
scores.remove("Bob");
// 遍历(无序)
for (key, value) in &scores {
println!("{key}: {value}");
}
// 判断存在
scores.contains_key("Alice");
scores.len()
scores.is_empty()
HashSet / BTreeMap / BTreeSet
use std::collections::{HashSet, BTreeMap, BTreeSet};
// HashSet:无序集合,元素唯一
let mut set: HashSet<i32> = HashSet::new();
set.insert(1);
set.insert(2);
set.insert(1); // 重复不插入
set.contains(&1); // true
let a: HashSet<i32> = [1, 2, 3].into();
let b: HashSet<i32> = [2, 3, 4].into();
let union: HashSet<_> = a.union(&b).collect(); // 并集
let intersection: HashSet<_> = a.intersection(&b).collect(); // 交集
let difference: HashSet<_> = a.difference(&b).collect(); // 差集
// BTreeMap:有序 HashMap(按 key 排序)
let mut map: BTreeMap<&str, i32> = BTreeMap::new();
map.insert("b", 2);
map.insert("a", 1);
// 遍历时按 key 字母序
// VecDeque:双端队列
use std::collections::VecDeque;
let mut deque: VecDeque<i32> = VecDeque::new();
deque.push_back(1);
deque.push_front(0);
deque.pop_front();
deque.pop_back();
枚举与模式匹配
// 基本枚举
#[derive(Debug)]
enum Direction {
North,
South,
East,
West,
}
// 带数据的枚举(每个变体可携带不同类型的数据)
#[derive(Debug)]
enum Message {
Quit, // 无数据
Move { x: i32, y: i32 }, // 命名字段
Write(String), // 单个值
ChangeColor(u8, u8, u8), // 元组
}
// 使用
let msg = Message::Move { x: 10, y: 20 };
let msg = Message::Write(String::from("hello"));
// match 解构
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})"),
}
// Option<T>:避免 null 的标准方式
let some_value: Option<i32> = Some(42);
let no_value: Option<i32> = None;
let doubled = match some_value {
Some(v) => Some(v * 2),
None => None,
};
// 等价于:
let doubled = some_value.map(|v| v * 2);
// 常用 Option 方法
some_value.unwrap() // 取值,None 时 panic
some_value.unwrap_or(0) // 取值,None 时用默认值
some_value.unwrap_or_else(|| 0) // 取值,None 时执行闭包
some_value.map(|v| v * 2) // 转换内部值
some_value.and_then(|v| if v > 0 { Some(v) } else { None })
some_value.or(Some(0)) // None 时替换
some_value.is_some()
some_value.is_none()
some_value? // 在返回 Option 的函数中:None 则提前返回
// Result<T, E>:错误处理的标准方式
let result: Result<i32, String> = Ok(42);
let error: Result<i32, String> = Err(String::from("出错了"));
result.unwrap()
result.unwrap_or(0)
result.map(|v| v * 2)
result.map_err(|e| format!("错误:{e}"))
result.is_ok()
result.is_err()
result? // 在返回 Result 的函数中:Err 则提前返回
结构体
// 定义
#[derive(Debug, Clone, PartialEq)]
struct User {
username: String,
email: String,
age: u32,
active: bool,
}
// 创建实例
let user = User {
username: String::from("alice"),
email: String::from("alice@example.com"),
age: 30,
active: true,
};
// 字段访问
println!("{}", user.username);
// 结构体更新语法(复用字段)
let user2 = User {
email: String::from("bob@example.com"),
..user // user 的其他字段被移动(username 是 String,会被移动)
};
// 元组结构体
struct Point(f64, f64);
struct Color(u8, u8, u8);
let p = Point(1.0, 2.0);
println!("{}", p.0);
// 单元结构体(不含字段,常用于实现 trait)
struct AlwaysEqual;
// 方法
impl User {
// 关联函数(类似静态方法,用 :: 调用)
fn new(username: &str, email: &str, age: u32) -> Self {
User {
username: username.to_string(),
email: email.to_string(),
age,
active: true,
}
}
// 方法(第一个参数是 self)
fn greet(&self) -> String {
format!("Hi, I'm {}!", self.username)
}
fn deactivate(&mut self) {
self.active = false;
}
fn into_username(self) -> String { // 消费 self
self.username
}
}
let mut u = User::new("alice", "alice@example.com", 30);
println!("{}", u.greet());
u.deactivate();
Trait(特征)
Trait 类似其他语言的接口,定义共享行为。
// 定义 trait
trait Animal {
// 必须实现的方法
fn name(&self) -> &str;
fn sound(&self) -> &str;
// 默认实现(可被覆盖)
fn describe(&self) -> String {
format!("{} 叫声是:{}", self.name(), self.sound())
}
}
struct Dog { name: String }
struct Cat { name: String }
impl Animal for Dog {
fn name(&self) -> &str { &self.name }
fn sound(&self) -> &str { "汪汪" }
}
impl Animal for Cat {
fn name(&self) -> &str { &self.name }
fn sound(&self) -> &str { "喵喵" }
fn describe(&self) -> String { // 覆盖默认实现
format!("猫咪 {} 优雅地叫:{}", self.name(), self.sound())
}
}
// Trait 作为参数(impl Trait 语法)
fn make_sound(animal: &impl Animal) {
println!("{}", animal.describe());
}
// Trait bound(泛型约束语法,更灵活)
fn make_sound<T: Animal>(animal: &T) {
println!("{}", animal.describe());
}
// 多个 Trait bound
fn process<T: Animal + std::fmt::Debug>(item: &T) { }
// 等价写法(where 子句,更清晰)
fn process<T>(item: &T) where T: Animal + std::fmt::Debug { }
// 返回实现了 Trait 的类型
fn make_animal(is_dog: bool) -> impl Animal {
if is_dog { Dog { name: "旺财".to_string() } }
else { Cat { name: "咪咪".to_string() } }
}
// dyn Trait(动态分发,运行时多态)
fn make_sounds(animals: &[Box<dyn Animal>]) {
for animal in animals {
println!("{}", animal.describe());
}
}
let animals: Vec<Box<dyn Animal>> = vec![
Box::new(Dog { name: "旺财".to_string() }),
Box::new(Cat { name: "咪咪".to_string() }),
];
常用标准库 Trait
// Display:格式化输出(用于 {})
use std::fmt;
impl fmt::Display for User {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "User({})", self.username)
}
}
// From / Into:类型转换
impl From<&str> for User {
fn from(s: &str) -> Self {
User::new(s, "", 0)
}
}
let u: User = "alice".into(); // Into 自动由 From 实现
// Clone / Copy
#[derive(Clone, Copy)] // derive 宏自动实现
struct Point { x: f64, y: f64 }
// Iterator:自定义迭代器
struct Counter { count: u32 }
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<u32> {
self.count += 1;
if self.count <= 5 { Some(self.count) } else { None }
}
}
泛型
// 泛型函数
fn largest<T: PartialOrd>(list: &[T]) -> &T {
let mut largest = &list[0];
for item in list {
if item > largest { largest = item; }
}
largest
}
// 泛型结构体
struct Pair<T> {
first: T,
second: T,
}
impl<T: std::fmt::Display + PartialOrd> Pair<T> {
fn cmp_display(&self) {
if self.first >= self.second {
println!("最大值是 {}", self.first);
} else {
println!("最大值是 {}", self.second);
}
}
}
// 泛型枚举(标准库的 Option 和 Result 就是这样实现的)
enum MyOption<T> {
Some(T),
None,
}
// 关联类型(比泛型更简洁)
trait Container {
type Item; // 关联类型
fn get(&self) -> &Self::Item;
}
错误处理
use std::fs;
use std::io;
use std::num::ParseIntError;
// ? 运算符:自动传播错误
fn read_number_from_file(path: &str) -> Result<i32, Box<dyn std::error::Error>> {
let content = fs::read_to_string(path)?; // io::Error 自动转换
let n: i32 = content.trim().parse()?; // ParseIntError 自动转换
Ok(n)
}
// 自定义错误类型(使用 thiserror 库)
use thiserror::Error;
#[derive(Debug, Error)]
enum AppError {
#[error("IO 错误:{0}")]
Io(#[from] io::Error),
#[error("解析错误:{0}")]
Parse(#[from] ParseIntError),
#[error("业务错误:{message}")]
Business { message: String },
#[error("找不到 ID 为 {id} 的用户")]
UserNotFound { id: u64 },
}
fn process(path: &str) -> Result<i32, AppError> {
let content = fs::read_to_string(path)?; // io::Error 通过 #[from] 自动转换
let n: i32 = content.trim().parse()?; // ParseIntError 自动转换
if n < 0 {
return Err(AppError::Business { message: "数字不能为负".to_string() });
}
Ok(n * 2)
}
// anyhow:快速错误处理(适合应用层,不适合库)
use anyhow::{anyhow, bail, Context, Result};
fn process_anyhow(path: &str) -> Result<i32> {
let content = fs::read_to_string(path)
.with_context(|| format!("无法读取文件:{path}"))?;
let n: i32 = content.trim().parse()
.context("文件内容不是有效数字")?;
if n < 0 {
bail!("数字不能为负:{n}"); // 等价于 return Err(anyhow!(...))
}
Ok(n)
}
迭代器与函数式编程
// 迭代器是惰性的,只有在消费时才执行
let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// 链式操作
let result: Vec<String> = v.iter()
.filter(|&&x| x % 2 == 0) // 过滤偶数
.map(|&x| x * x) // 平方
.take(3) // 只取前 3 个
.map(|x| x.to_string()) // 转 String
.collect(); // 收集为 Vec
// result = ["4", "16", "36"]
// 常用迭代器方法
v.iter().sum::<i32>() // 求和
v.iter().product::<i32>() // 乘积
v.iter().count() // 计数
v.iter().max() // 最大值 Option
v.iter().min() // 最小值 Option
v.iter().any(|&x| x > 5) // 任意满足
v.iter().all(|&x| x > 0) // 全部满足
v.iter().find(|&&x| x > 5) // 找到第一个满足的元素
v.iter().position(|&x| x == 5) // 找到位置
v.iter().enumerate() // 添加索引
v.iter().zip([1, 2, 3].iter()) // 配对
v.iter().flat_map(|&x| [x, x * 10]) // 映射并展平
v.iter().fold(0, |acc, &x| acc + x) // 归约
v.iter().scan(0, |state, &x| { // 有状态映射
*state += x;
Some(*state)
})
v.iter().peekable() // 可以窥视下一个元素
v.iter().skip(2).take(3) // 跳过再取
v.iter().step_by(2) // 步长迭代
v.iter().chain(v.iter()) // 连接两个迭代器
v.iter().rev() // 反转(需 DoubleEndedIterator)
// 迭代器类型
v.iter() // -> Iterator<Item = &i32>(借用)
v.iter_mut() // -> Iterator<Item = &mut i32>(可变借用)
v.into_iter() // -> Iterator<Item = i32>(消费,移动所有权)
// collect 到不同集合
use std::collections::{HashMap, HashSet};
let set: HashSet<i32> = v.iter().cloned().collect();
let map: HashMap<i32, i32> = v.iter().map(|&x| (x, x * x)).collect();
智能指针
use std::rc::Rc;
use std::cell::RefCell;
use std::sync::{Arc, Mutex};
// Box<T>:堆分配,单一所有权
// 用途:递归类型、trait 对象、大数据转移所有权
let b = Box::new(5);
println!("{}", *b);
// 递归类型(编译器无法推断大小,必须用 Box)
enum List {
Cons(i32, Box<List>),
Nil,
}
// Rc<T>:引用计数,单线程多所有权
let a = Rc::new(5);
let b = Rc::clone(&a); // 引用计数 +1,不是深拷贝
println!("引用计数:{}", Rc::strong_count(&a)); // 2
// 两个变量离开作用域后自动释放
// RefCell<T>:运行时借用检查(内部可变性)
// 用途:在不可变引用场景中实现可变性
let data = RefCell::new(vec![1, 2, 3]);
data.borrow().len(); // 不可变借用
data.borrow_mut().push(4); // 可变借用(运行时检查,违规则 panic)
// Rc<RefCell<T>>:多所有者 + 内部可变性(单线程)
let shared = Rc::new(RefCell::new(vec![1, 2]));
let clone1 = Rc::clone(&shared);
let clone2 = Rc::clone(&shared);
clone1.borrow_mut().push(3);
println!("{:?}", clone2.borrow()); // [1, 2, 3]
// Arc<T>:原子引用计数(多线程安全版 Rc)
let arc = Arc::new(5);
let arc2 = Arc::clone(&arc);
std::thread::spawn(move || println!("{}", arc2));
// Mutex<T>:互斥锁(多线程可变共享)
let counter = Arc::new(Mutex::new(0));
let c = Arc::clone(&counter);
std::thread::spawn(move || {
let mut num = c.lock().unwrap(); // 获取锁
*num += 1;
}); // 离开作用域自动释放锁
// RwLock<T>:读写锁(允许多读一写)
use std::sync::RwLock;
let lock = RwLock::new(5);
let r1 = lock.read().unwrap();
let r2 = lock.read().unwrap(); // 多个读锁同时存在
// let w = lock.write().unwrap(); // 有读锁时不能写
并发
线程
use std::thread;
use std::sync::{Arc, Mutex};
use std::time::Duration;
// 创建线程
let handle = thread::spawn(|| {
for i in 1..=5 {
println!("子线程:{i}");
thread::sleep(Duration::from_millis(100));
}
});
// 等待线程结束
handle.join().unwrap();
// move 闭包:将所有权移入线程
let v = vec![1, 2, 3];
let handle = thread::spawn(move || {
println!("{:?}", v); // v 被移入线程
});
handle.join().unwrap();
// 线程间共享数据
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let c = Arc::clone(&counter);
let h = thread::spawn(move || {
let mut num = c.lock().unwrap();
*num += 1;
});
handles.push(h);
}
for h in handles { h.join().unwrap(); }
println!("最终计数:{}", *counter.lock().unwrap());
消息传递(Channel)
use std::sync::mpsc; // multiple producer, single consumer
// 单发送者
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
tx.send(String::from("hello")).unwrap();
tx.send(String::from("world")).unwrap();
// tx 离开作用域,channel 关闭
});
// 接收
let msg = rx.recv().unwrap(); // 阻塞等待
println!("{msg}");
// 遍历接收所有消息(直到 channel 关闭)
for msg in rx {
println!("{msg}");
}
// 多发送者
let (tx, rx) = mpsc::channel::<String>();
let tx2 = tx.clone();
thread::spawn(move || tx.send("from tx".to_string()).unwrap());
thread::spawn(move || tx2.send("from tx2".to_string()).unwrap());
for msg in rx { println!("{msg}"); }
异步编程(Tokio)
Rust 的异步通过 async/await + 运行时(Runtime)实现,最主流的运行时是 Tokio。
# Cargo.toml
[dependencies]
tokio = { version = "1", features = ["full"] }
基础用法
use tokio::time::{sleep, Duration};
// async fn 返回 Future,需要 .await 执行
async fn say_hello() {
println!("Hello");
sleep(Duration::from_millis(100)).await;
println!("World");
}
// #[tokio::main] 启动运行时
#[tokio::main]
async fn main() {
say_hello().await;
}
// 并发执行多个任务
#[tokio::main]
async fn main() {
// tokio::join!:并发等待多个 Future
let (r1, r2) = tokio::join!(
async_task_1(),
async_task_2(),
);
// tokio::spawn:后台任务(不等待)
let handle = tokio::spawn(async {
sleep(Duration::from_secs(1)).await;
42
});
let result = handle.await.unwrap();
// select!:等待最先完成的 Future
tokio::select! {
val = async_task_1() => println!("task1 先完成:{val}"),
val = async_task_2() => println!("task2 先完成:{val}"),
}
}
异步网络请求(reqwest)
use reqwest;
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize)]
struct User {
id: u32,
name: String,
email: String,
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let client = reqwest::Client::new();
// GET 请求
let user: User = client
.get("https://jsonplaceholder.typicode.com/users/1")
.send()
.await?
.error_for_status()? // 非 2xx 返回错误
.json()
.await?;
println!("{user:?}");
// POST 请求
#[derive(Serialize)]
struct NewUser { name: String, email: String }
let new_user = NewUser {
name: "Alice".to_string(),
email: "alice@example.com".to_string(),
};
let response = client
.post("https://jsonplaceholder.typicode.com/users")
.json(&new_user)
.header("Authorization", "Bearer token")
.send()
.await?
.error_for_status()?;
println!("状态码:{}", response.status());
Ok(())
}
异步文件 I/O
use tokio::fs;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// 读文件
let content = fs::read_to_string("input.txt").await?;
// 写文件
fs::write("output.txt", "Hello, Async!").await?;
// 流式读取
let mut file = fs::File::open("large.txt").await?;
let mut buffer = Vec::new();
file.read_to_end(&mut buffer).await?;
// 流式写入
let mut file = fs::File::create("result.txt").await?;
file.write_all(b"Hello").await?;
file.flush().await?;
Ok(())
}
宏
// 常用内置宏
println!("Hello, {name}!"); // 打印并换行
print!("无换行");
eprintln!("错误输出"); // 输出到 stderr
format!("{} + {} = {}", 1, 2, 3) // 格式化为 String
vec![1, 2, 3] // 创建 Vec
panic!("不可恢复的错误") // 程序崩溃
assert!(1 + 1 == 2) // 断言
assert_eq!(1 + 1, 2) // 相等断言(失败时显示两个值)
assert_ne!(1, 2) // 不等断言
todo!() // 标记未实现(运行时 panic)
unimplemented!() // 标记不支持(运行时 panic)
unreachable!() // 标记不可达代码
dbg!(&value) // 调试输出(含文件名和行号)
include_str!("file.txt") // 编译期嵌入文件内容为 &str
include_bytes!("file.bin") // 编译期嵌入文件内容为 &[u8]
env!("CARGO_PKG_VERSION") // 编译期读取环境变量
// derive 宏:自动实现 trait
#[derive(
Debug, // {:?} 格式化
Clone, // .clone() 方法
Copy, // 栈上复制语义
PartialEq, // == 运算符
Eq, // 完全相等(配合 PartialEq)
PartialOrd, // < > <= >= 运算符
Ord, // 完全排序
Hash, // 用于 HashMap key
Default, // Default::default()
Serialize, // serde JSON 序列化
Deserialize, // serde JSON 反序列化
)]
struct MyStruct {
field: i32,
}
序列化(serde)
[dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = "1"
use serde::{Deserialize, Serialize};
use serde_json;
#[derive(Debug, Serialize, Deserialize)]
struct User {
id: u32,
name: String,
email: String,
#[serde(skip_serializing_if = "Option::is_none")]
avatar: Option<String>, // None 时不输出字段
#[serde(rename = "created_at")]
created: String, // JSON key 重命名
#[serde(skip)]
password: String, // 序列化/反序列化时跳过
}
// 序列化为 JSON
let user = User {
id: 1, name: "Alice".to_string(), email: "a@b.com".to_string(),
avatar: None, created: "2024-01-01".to_string(), password: "secret".to_string(),
};
let json = serde_json::to_string(&user)?; // 紧凑格式
let json = serde_json::to_string_pretty(&user)?; // 美化格式
// 反序列化
let user: User = serde_json::from_str(&json)?;
// 动态 JSON(Value 类型)
use serde_json::{json, Value};
let v: Value = json!({
"name": "Alice",
"scores": [100, 95, 88],
"active": true
});
println!("{}", v["name"]); // "Alice"
println!("{}", v["scores"][0]); // 100
// 解析为动态 Value
let v: Value = serde_json::from_str(r#"{"x": 1}"#)?;
let x = v["x"].as_i64().unwrap();
测试
// src/lib.rs 或 src/main.rs
pub fn add(a: i32, b: i32) -> i32 { a + b }
pub fn divide(a: f64, b: f64) -> Result<f64, String> {
if b == 0.0 { Err("除数不能为零".to_string()) }
else { Ok(a / b) }
}
#[cfg(test)] // 只在 cargo test 时编译
mod tests {
use super::*; // 引入父模块的所有内容
#[test]
fn test_add() {
assert_eq!(add(2, 3), 5);
assert_ne!(add(2, 3), 6);
}
#[test]
fn test_divide_ok() {
let result = divide(10.0, 2.0).unwrap();
assert!((result - 5.0).abs() < f64::EPSILON);
}
#[test]
fn test_divide_by_zero() {
assert!(divide(10.0, 0.0).is_err());
}
#[test]
#[should_panic(expected = "越界")] // 预期 panic
fn test_panic() {
let v = vec![1, 2, 3];
v[10]; // 实际上不含"越界"字样,此测试会失败
}
#[test]
#[ignore] // 跳过(cargo test -- --ignored 可单独运行)
fn expensive_test() {
// 耗时测试
}
}
// 集成测试(tests/ 目录)
// tests/integration_test.rs
use my_crate::add;
#[test]
fn test_add_integration() {
assert_eq!(add(2, 3), 5);
}
cargo test # 运行所有测试
cargo test test_add # 运行名称包含 test_add 的测试
cargo test -- --nocapture # 显示 println! 输出
cargo test -- --test-threads=1 # 单线程运行(避免并发影响)
cargo test -- --ignored # 运行被 ignore 的测试
常用标准库
// 文件 I/O
use std::fs;
use std::io::{self, BufRead, Write};
let content = fs::read_to_string("file.txt")?;
fs::write("file.txt", "content")?;
fs::copy("src.txt", "dst.txt")?;
fs::rename("old.txt", "new.txt")?;
fs::remove_file("file.txt")?;
fs::create_dir_all("a/b/c")?;
fs::remove_dir_all("dir")?;
// 逐行读取(大文件推荐)
let file = fs::File::open("file.txt")?;
for line in io::BufReader::new(file).lines() {
println!("{}", line?);
}
// 路径操作
use std::path::{Path, PathBuf};
let path = Path::new("/home/user/file.txt");
path.exists()
path.is_file()
path.is_dir()
path.extension() // Some("txt")
path.file_name() // Some("file.txt")
path.file_stem() // Some("file")
path.parent() // Some("/home/user")
let mut buf = PathBuf::from("/home/user");
buf.push("file.txt");
// 环境变量 & 命令行
use std::env;
let args: Vec<String> = env::args().collect();
let home = env::var("HOME")?;
env::set_var("KEY", "value");
let cwd = env::current_dir()?;
// 进程
use std::process::{Command, exit};
let output = Command::new("ls")
.args(["-la", "/tmp"])
.output()?;
println!("{}", String::from_utf8_lossy(&output.stdout));
exit(0);
// 时间
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
let start = Instant::now();
// ... 执行代码 ...
println!("耗时:{:?}", start.elapsed());
let timestamp = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
常用第三方库
| 库 | 用途 |
|---|---|
tokio |
异步运行时(标配) |
reqwest |
HTTP 客户端(基于 tokio) |
axum |
Web 框架(轻量、高性能,tokio 原生) |
actix-web |
Web 框架(高性能) |
serde + serde_json |
序列化/反序列化 |
anyhow |
应用层错误处理 |
thiserror |
库层自定义错误类型 |
clap |
命令行参数解析 |
tracing |
结构化日志 + 追踪 |
sqlx |
异步数据库(编译期 SQL 检查) |
diesel |
ORM(同步,强类型) |
redis |
Redis 客户端 |
uuid |
UUID 生成 |
chrono |
时间日期处理 |
regex |
正则表达式 |
rayon |
数据并行(并行迭代器) |
crossbeam |
并发原语(channel、无锁数据结构) |
dashmap |
并发 HashMap |
bytes |
高效字节缓冲区 |
flate2 |
gzip/zlib 压缩 |
base64 |
Base64 编解码 |
Axum Web 服务示例
[dependencies]
axum = "0.7"
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tower-http = { version = "0.5", features = ["cors", "trace"] }
use axum::{
extract::{Path, Query, State},
http::StatusCode,
response::Json,
routing::{delete, get, post, put},
Router,
};
use serde::{Deserialize, Serialize};
use std::sync::{Arc, Mutex};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
struct User {
id: u64,
name: String,
email: String,
}
// 应用状态
type Db = Arc<Mutex<HashMap<u64, User>>>;
#[tokio::main]
async fn main() {
let db: Db = Arc::new(Mutex::new(HashMap::new()));
let app = Router::new()
.route("/users", get(list_users).post(create_user))
.route("/users/:id", get(get_user).put(update_user).delete(delete_user))
.with_state(db);
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
println!("监听 http://localhost:3000");
axum::serve(listener, app).await.unwrap();
}
async fn list_users(State(db): State<Db>) -> Json<Vec<User>> {
let db = db.lock().unwrap();
Json(db.values().cloned().collect())
}
async fn get_user(
State(db): State<Db>,
Path(id): Path<u64>,
) -> Result<Json<User>, StatusCode> {
let db = db.lock().unwrap();
db.get(&id)
.cloned()
.map(Json)
.ok_or(StatusCode::NOT_FOUND)
}
#[derive(Deserialize)]
struct CreateUser { name: String, email: String }
async fn create_user(
State(db): State<Db>,
Json(payload): Json<CreateUser>,
) -> (StatusCode, Json<User>) {
let mut db = db.lock().unwrap();
let id = db.len() as u64 + 1;
let user = User { id, name: payload.name, email: payload.email };
db.insert(id, user.clone());
(StatusCode::CREATED, Json(user))
}
async fn update_user(
State(db): State<Db>,
Path(id): Path<u64>,
Json(payload): Json<CreateUser>,
) -> Result<Json<User>, StatusCode> {
let mut db = db.lock().unwrap();
if let Some(user) = db.get_mut(&id) {
user.name = payload.name;
user.email = payload.email;
Ok(Json(user.clone()))
} else {
Err(StatusCode::NOT_FOUND)
}
}
async fn delete_user(
State(db): State<Db>,
Path(id): Path<u64>,
) -> StatusCode {
let mut db = db.lock().unwrap();
if db.remove(&id).is_some() { StatusCode::NO_CONTENT }
else { StatusCode::NOT_FOUND }
}
最佳实践
-
拥抱编译器:Rust 的编译错误信息极为详细,认真阅读错误提示往往直接给出修复建议。遇到借用检查器报错时,优先思考数据的生命周期和所有权归属。
-
优先使用
?传播错误:避免.unwrap()在生产代码中使用,除非你确定该值一定存在(如程序初始化阶段)。 -
库用
thiserror,应用用anyhow:库应定义具体错误类型方便调用方处理,应用层用anyhow快速汇聚所有错误。 -
结构体派生常用 Trait:养成给数据结构加
#[derive(Debug, Clone)]的习惯,Debug方便调试,Clone减少借用冲突。 -
多用迭代器链式调用:比手写循环更安全、更惯用,编译器通常能优化得和循环一样快甚至更快。
-
Arc<Mutex<T>>是多线程共享状态的标准模式:单线程用Rc<RefCell<T>>,多线程用Arc<Mutex<T>>或Arc<RwLock<T>>(读多写少时)。 -
避免过早优化:先用
clone()让代码跑通,再根据性能分析决定是否消除克隆。编写正确代码比编写"零克隆"代码更重要。 -
善用
clippy:cargo clippy会指出大量不惯用写法和潜在问题,是学习 Rust 惯用法的最佳工具之一。 -
使用
cargo fmt统一格式:在 CI 中加入cargo fmt --check保证代码风格一致。 -
从已有代码学习:阅读
std标准库源码、tokio、axum等优秀库的源码是提升 Rust 水平最快的方式。