Rust 完全教程
核心理念
Rust 三大支柱:
- 所有权 (Ownership): 内存安全无 GC
- 零成本抽象: 高层抽象无运行时开销
- 并发安全: 编译期消除数据竞争
设计哲学: "如果编译通过,就不会崩溃"
环境配置
安装
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh rustup update # 更新到最新版本
常用工具
- rustc: 编译器
- cargo: 包管理器与构建工具
- rustfmt: 代码格式化
- clippy: Lint 工具
- rust-analyzer: LSP 服务器
cargo new project_name # 创建项目 cargo build # 构建 cargo run # 运行 cargo test # 测试 cargo doc --open # 生成文档 cargo clippy # 代码检查
基础语法
变量与可变性
// 默认不可变 let x = 5; // x = 6; // 错误! // 显式声明可变 let mut y = 5; y = 6; // OK // 常量: 必须标注类型,编译时求值 const MAX_POINTS: u32 = 100_000; // 遮蔽 (shadowing): 可改变类型 let spaces = " "; let spaces = spaces.len();
Tips: 优先使用不可变,需要时才用 mut
数据类型
标量类型
// 整数: i8/u8, i16/u16, i32/u32, i64/u64, i128/u128, isize/usize let a: i32 = 42; let b = 0xff; // 十六进制 let c = 1_000_000; // 下划线分隔 // 浮点: f32, f64 (默认) let f = 2.0; // f64 // 布尔 let t = true; // 字符: Unicode 标量值 let emoji = '😀';
复合类型
// 元组: 固定长度,类型可不同 let tup: (i32, f64, u8) = (500, 6.4, 1); let (x, y, z) = tup; // 解构 let first = tup.0; // 索引访问 // 数组: 固定长度,类型相同 let arr = [1, 2, 3, 4, 5]; let arr: [i32; 5] = [1, 2, 3, 4, 5]; let arr = [3; 5]; // [3, 3, 3, 3, 3]
函数
// 参数必须标注类型
fn add(x: i32, y: i32) -> i32 {
x + y // 表达式,无分号
}
// 语句 vs 表达式
fn example() -> i32 {
let x = 5; // 语句
x + 1 // 表达式,作为返回值
}
// 发散函数
fn diverges() -> ! {
panic!("This function never returns");
}
控制流
// if 表达式
let number = if condition { 5 } else { 6 };
// loop 无限循环
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2; // break 可返回值
}
};
// while 条件循环
while number != 0 {
number -= 1;
}
// for 迭代
for element in array.iter() {
println!("{}", element);
}
for number in (1..4).rev() { // 范围反转
println!("{}", number);
}
所有权系统
核心规则
- 每个值有一个*所有者*
- 同时只能有*一个*所有者
- 所有者离开作用域,值被丢弃
{
let s = String::from("hello"); // s 有效
// 使用 s
} // s 离开作用域,内存被释放
移动 (Move)
let s1 = String::from("hello");
let s2 = s1; // s1 的值移动到 s2,s1 失效
// println!("{}", s1); // 错误! s1 已失效
// 对于栈上数据(实现了 Copy trait),是复制
let x = 5;
let y = x; // x 仍有效
设计思路: 防止二次释放 (double free)
借用 (Borrowing)
fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1); // 借用,不转移所有权
println!("'{}' length is {}", s1, len); // s1 仍有效
}
fn calculate_length(s: &String) -> usize {
s.len()
} // s 离开作用域,但不拥有数据,所以不释放
可变借用
fn main() {
let mut s = String::from("hello");
change(&mut s);
}
fn change(s: &mut String) {
s.push_str(", world");
}
关键限制:
- 同一时间,*要么*多个不可变借用,*要么*一个可变借用
- 借用必须总是有效(引用生命周期)
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; // OK
Slice
let s = String::from("hello world");
let hello = &s[0..5]; // 字符串 slice
let world = &s[6..11];
let slice = &s[..]; // 整个字符串
// 函数签名使用 &str (字符串 slice)
fn first_word(s: &str) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
// 数组 slice
let a = [1, 2, 3, 4, 5];
let slice = &a[1..3]; // 类型: &[i32]
结构体与枚举
结构体
// 经典结构体
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
let mut user1 = User {
email: String::from("user@example.com"),
username: String::from("user123"),
active: true,
sign_in_count: 1,
};
user1.email = String::from("new@example.com");
// 字段初始化简写
fn build_user(email: String, username: String) -> User {
User {
email,
username,
active: true,
sign_in_count: 1,
}
}
// 结构体更新语法
let user2 = User {
email: String::from("another@example.com"),
..user1 // 其余字段从 user1 复制/移动
};
// 元组结构体
struct Color(i32, i32, i32);
let black = Color(0, 0, 0);
// 单元结构体
struct AlwaysEqual;
方法
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
// 方法: 第一个参数是 self
fn area(&self) -> u32 {
self.width * self.height
}
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
// 关联函数: 不以 self 为参数(类似静态方法)
fn square(size: u32) -> Rectangle {
Rectangle {
width: size,
height: size,
}
}
}
let rect = Rectangle { width: 30, height: 50 };
println!("Area: {}", rect.area());
let sq = Rectangle::square(25);
枚举
// 基本枚举
enum IpAddrKind {
V4,
V6,
}
// 枚举变体携带数据
enum IpAddr {
V4(u8, u8, u8, u8),
V6(String),
}
let home = IpAddr::V4(127, 0, 0, 1);
let loopback = IpAddr::V6(String::from("::1"));
// 复杂枚举
enum Message {
Quit, // 无数据
Move { x: i32, y: i32 }, // 匿名结构体
Write(String), // 单个字符串
ChangeColor(i32, i32, i32), // 三个整数
}
impl Message {
fn call(&self) {
// 方法体
}
}
Option<T>
// Rust 无 null,使用 Option 表达"可能无值"
enum Option<T> {
Some(T),
None,
}
let some_number = Some(5);
let some_string = Some("a string");
let absent_number: Option<i32> = None;
// 必须处理 None 情况才能使用值
fn plus_one(x: Option<i32>) -> Option<i32> {
match x {
Some(i) => Some(i + 1),
None => None,
}
}
match 模式匹配
enum Coin {
Penny,
Nickel,
Dime,
Quarter(UsState),
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => {
println!("Lucky penny!");
1
}
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter(state) => {
println!("State quarter from {:?}!", state);
25
}
}
}
// match 必须穷尽所有可能
let dice_roll = 9;
match dice_roll {
3 => add_fancy_hat(),
7 => remove_fancy_hat(),
_ => reroll(), // 通配符
}
// if let: 只关心一种情况
let some_value = Some(3);
if let Some(3) = some_value {
println!("three");
}
泛型、Trait 与生命周期
泛型
// 函数泛型
fn largest<T: PartialOrd>(list: &[T]) -> &T {
let mut largest = &list[0];
for item in list {
if item > largest {
largest = item;
}
}
largest
}
// 结构体泛型
struct Point<T> {
x: T,
y: T,
}
impl<T> Point<T> {
fn x(&self) -> &T {
&self.x
}
}
// 为特定类型实现方法
impl Point<f32> {
fn distance_from_origin(&self) -> f32 {
(self.x.powi(2) + self.y.powi(2)).sqrt()
}
}
// 多个泛型参数
struct Point2<T, U> {
x: T,
y: U,
}
// 枚举泛型
enum Result<T, E> {
Ok(T),
Err(E),
}
零成本抽象: 泛型在编译时单态化,无运行时开销
Trait
// 定义 trait
pub trait Summary {
fn summarize(&self) -> String;
// 默认实现
fn summarize_author(&self) -> String {
String::from("(Read more...)")
}
}
// 为类型实现 trait
pub struct NewsArticle {
pub headline: String,
pub content: String,
}
impl Summary for NewsArticle {
fn summarize(&self) -> String {
format!("{}: {}", self.headline, self.content)
}
}
// trait 作为参数
pub fn notify(item: &impl Summary) {
println!("Breaking news! {}", item.summarize());
}
// trait bound 语法
pub fn notify<T: Summary>(item: &T) {
println!("Breaking news! {}", item.summarize());
}
// 多个 trait bound
pub fn notify<T: Summary + Display>(item: &T) {}
// where 子句(可读性更好)
fn some_function<T, U>(t: &T, u: &U) -> i32
where
T: Display + Clone,
U: Clone + Debug,
{
// ...
}
// 返回实现 trait 的类型
fn returns_summarizable() -> impl Summary {
NewsArticle {
headline: String::from("Title"),
content: String::from("Content"),
}
}
常用 Trait
// Clone: 深拷贝
#[derive(Clone)]
struct MyStruct;
// Copy: 栈上按位复制(隐含 Clone)
#[derive(Copy, Clone)]
struct Point { x: i32, y: i32 }
// Debug: 格式化输出
#[derive(Debug)]
struct Rectangle { width: u32, height: u32 }
// PartialEq/Eq: 相等比较
#[derive(PartialEq, Eq)]
struct Person { name: String }
// PartialOrd/Ord: 排序比较
#[derive(PartialOrd, Ord, PartialEq, Eq)]
struct Priority(i32);
// Default: 默认值
#[derive(Default)]
struct Config { timeout: u32 }
// From/Into: 类型转换
impl From<i32> for Number {
fn from(item: i32) -> Self {
Number { value: item }
}
}
// Iterator: 迭代器
struct Counter { count: u32 }
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
self.count += 1;
if self.count < 6 {
Some(self.count)
} else {
None
}
}
}
生命周期
// 生命周期注解: 描述引用之间的关系
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
// 结构体中的生命周期
struct ImportantExcerpt<'a> {
part: &'a str,
}
impl<'a> ImportantExcerpt<'a> {
fn level(&self) -> i32 {
3
}
// 生命周期省略规则
fn announce_and_return_part(&self, announcement: &str) -> &str {
println!("Attention please: {}", announcement);
self.part
}
}
// 静态生命周期: 存活于整个程序
let s: &'static str = "I have a static lifetime.";
生命周期省略规则:
- 每个引用参数获得独立生命周期
- 若只有一个输入生命周期,赋给所有输出
- 若多个输入且其中一个是 &self,其生命周期赋给所有输出
错误处理
panic!
// 不可恢复错误
panic!("crash and burn");
// RUST_BACKTRACE=1 获取回溯
Result<T, E>
use std::fs::File;
use std::io::{self, Read};
// 基本处理
fn read_username_from_file() -> Result<String, io::Error> {
let mut f = File::open("username.txt")?; // ? 操作符传播错误
let mut s = String::new();
f.read_to_string(&mut s)?;
Ok(s)
}
// ? 操作符等价于:
let mut f = match File::open("username.txt") {
Ok(file) => file,
Err(e) => return Err(e),
};
// 链式调用
fn read_username_from_file() -> Result<String, io::Error> {
let mut s = String::new();
File::open("username.txt")?.read_to_string(&mut s)?;
Ok(s)
}
// main 也可返回 Result
fn main() -> Result<(), Box<dyn std::error::Error>> {
let f = File::open("hello.txt")?;
Ok(())
}
// 自定义错误类型
use std::fmt;
#[derive(Debug)]
struct MyError {
details: String,
}
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.details)
}
}
impl std::error::Error for MyError {}
Tips:
- unwrap(): 遇错 panic
- expect("msg"): 带消息的 unwrap
- 生产代码使用 ? 或 match
集合类型
Vec<T>
// 创建
let v: Vec<i32> = Vec::new();
let v = vec![1, 2, 3]; // 宏
// 更新
let mut v = Vec::new();
v.push(5);
v.push(6);
// 访问
let third: &i32 = &v[2]; // 越界会 panic
let third: Option<&i32> = v.get(2); // 返回 Option
// 遍历
for i in &v {
println!("{}", i);
}
for i in &mut v {
*i += 50; // 解引用修改
}
// 存储多种类型(用枚举)
enum SpreadsheetCell {
Int(i32),
Float(f64),
Text(String),
}
let row = vec![
SpreadsheetCell::Int(3),
SpreadsheetCell::Text(String::from("blue")),
SpreadsheetCell::Float(10.12),
];
String
// 创建
let mut s = String::new();
let s = "initial contents".to_string();
let s = String::from("initial contents");
// 更新
s.push_str("bar");
s.push('!');
let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2; // s1 被移动,不能再使用
// format! 宏(不取得所有权)
let s = format!("{}-{}-{}", s1, s2, s3);
// 索引: Rust 不支持字符串索引!
let s = String::from("hello");
// let h = s[0]; // 错误!
// 原因: UTF-8 编码,字节≠字符
let hello = "Здравствуйте";
let s = &hello[0..4]; // Зд (每个字符2字节)
// 遍历
for c in "नमस्ते".chars() {
println!("{}", c);
}
for b in "नमस्ते".bytes() {
println!("{}", b);
}
HashMap<K, V>
use std::collections::HashMap;
// 创建
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
// 从元组 Vec 构建
let teams = vec![String::from("Blue"), String::from("Yellow")];
let initial_scores = vec![10, 50];
let scores: HashMap<_, _> = teams.iter().zip(initial_scores.iter()).collect();
// 访问
let team_name = String::from("Blue");
let score = scores.get(&team_name); // Option<&V>
// 遍历
for (key, value) in &scores {
println!("{}: {}", key, value);
}
// 更新
scores.insert(String::from("Blue"), 25); // 覆盖
// 只在键不存在时插入
scores.entry(String::from("Yellow")).or_insert(50);
// 基于旧值更新
let text = "hello world wonderful world";
let mut map = HashMap::new();
for word in text.split_whitespace() {
let count = map.entry(word).or_insert(0);
*count += 1;
}
闭包与迭代器
闭包
// 基本语法
let add_one = |x: i32| x + 1;
let add_one = |x| x + 1; // 类型推断
// 多行闭包
let expensive_closure = |num| {
println!("calculating slowly...");
thread::sleep(Duration::from_secs(2));
num
};
// 捕获环境
let x = 4;
let equal_to_x = |z| z == x; // 捕获 x
// 三种捕获方式
// 1. FnOnce: 获取所有权
// 2. FnMut: 可变借用
// 3. Fn: 不可变借用
let mut list = vec![1, 2, 3];
let mut borrows_mutably = || list.push(7); // FnMut
borrows_mutably();
// move 关键字: 强制取得所有权
let x = vec![1, 2, 3];
let equal_to_x = move |z| z == x;
// println!("{:?}", x); // 错误! x 已移动
// 作为参数
fn apply<F>(f: F, x: i32) -> i32
where
F: Fn(i32) -> i32,
{
f(x)
}
let result = apply(|x| x * 2, 5);
迭代器
let v1 = vec![1, 2, 3];
// 创建迭代器
let v1_iter = v1.iter(); // 不可变引用
let v1_iter = v1.iter_mut(); // 可变引用
let v1_iter = v1.into_iter(); // 获取所有权
// 消耗适配器: 消耗迭代器
let total: i32 = v1.iter().sum();
// 迭代器适配器: 产生新迭代器
let v2: Vec<_> = v1.iter().map(|x| x + 1).collect();
// 链式调用
let v1 = vec![1, 2, 3];
let v2: Vec<_> = v1
.iter()
.filter(|x| *x % 2 == 0)
.map(|x| x * 2)
.collect();
// 自定义迭代器
struct Counter {
count: u32,
}
impl Counter {
fn new() -> Counter {
Counter { count: 0 }
}
}
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
if self.count < 5 {
self.count += 1;
Some(self.count)
} else {
None
}
}
}
// 使用
let sum: u32 = Counter::new()
.zip(Counter::new().skip(1))
.map(|(a, b)| a * b)
.filter(|x| x % 3 == 0)
.sum();
性能: 迭代器是零成本抽象,编译后与手写循环一样快
智能指针
Box<T>
// 堆分配
let b = Box::new(5);
println!("b = {}", b);
// 递归类型
enum List {
Cons(i32, Box<List>),
Nil,
}
use List::{Cons, Nil};
let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
// 实现 Deref
use std::ops::Deref;
struct MyBox<T>(T);
impl<T> MyBox<T> {
fn new(x: T) -> MyBox<T> {
MyBox(x)
}
}
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
let x = 5;
let y = MyBox::new(x);
assert_eq!(5, *y); // 解引用强制转换
Rc<T>
use std::rc::Rc;
// 引用计数: 多个所有者
enum List {
Cons(i32, Rc<List>),
Nil,
}
use List::{Cons, Nil};
let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
println!("count after creating a = {}", Rc::strong_count(&a));
let b = Cons(3, Rc::clone(&a)); // 增加引用计数
let c = Cons(4, Rc::clone(&a));
println!("count after creating c = {}", Rc::strong_count(&a));
注意: Rc<T> 仅用于单线程
RefCell<T>
use std::cell::RefCell;
// 内部可变性: 运行时检查借用规则
let x = RefCell::new(5);
*x.borrow_mut() += 1; // 可变借用
println!("{}", x.borrow()); // 不可变借用
// 组合 Rc<RefCell<T>>: 多个可变所有者
#[derive(Debug)]
enum List {
Cons(Rc<RefCell<i32>>, Rc<List>),
Nil,
}
let value = Rc::new(RefCell::new(5));
let a = Rc::new(Cons(Rc::clone(&value), Rc::new(Nil)));
*value.borrow_mut() += 10; // 修改共享值
循环引用与 Weak<T>
use std::rc::{Rc, Weak};
use std::cell::RefCell;
#[derive(Debug)]
struct Node {
value: i32,
parent: RefCell<Weak<Node>>,
children: RefCell<Vec<Rc<Node>>>,
}
let leaf = Rc::new(Node {
value: 3,
parent: RefCell::new(Weak::new()),
children: RefCell::new(vec![]),
});
let branch = Rc::new(Node {
value: 5,
parent: RefCell::new(Weak::new()),
children: RefCell::new(vec![Rc::clone(&leaf)]),
});
*leaf.parent.borrow_mut() = Rc::downgrade(&branch);
// Weak 不增加强引用计数,防止循环引用
并发编程
线程
use std::thread;
use std::time::Duration;
// 创建线程
let handle = thread::spawn(|| {
for i in 1..10 {
println!("hi number {} from spawned thread!", i);
thread::sleep(Duration::from_millis(1));
}
});
handle.join().unwrap(); // 等待线程结束
// move 捕获环境
let v = vec![1, 2, 3];
let handle = thread::spawn(move || {
println!("Here's a vector: {:?}", v);
});
handle.join().unwrap();
消息传递
use std::sync::mpsc; // multiple producer, single consumer
use std::thread;
// 创建通道
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let val = String::from("hi");
tx.send(val).unwrap();
// println!("{}", val); // 错误! val 已移动
});
let received = rx.recv().unwrap(); // 阻塞等待
println!("Got: {}", received);
// 多个发送者
let (tx, rx) = mpsc::channel();
let tx1 = tx.clone();
thread::spawn(move || {
let vals = vec![
String::from("hi"),
String::from("from"),
String::from("the"),
String::from("thread"),
];
for val in vals {
tx.send(val).unwrap();
thread::sleep(Duration::from_secs(1));
}
});
thread::spawn(move || {
let vals = vec![
String::from("more"),
String::from("messages"),
];
for val in vals {
tx1.send(val).unwrap();
thread::sleep(Duration::from_secs(1));
}
});
// rx 作为迭代器
for received in rx {
println!("Got: {}", received);
}
共享状态
use std::sync::{Arc, Mutex};
use std::thread;
// Mutex: 互斥锁
let m = Mutex::new(5);
{
let mut num = m.lock().unwrap();
*num = 6;
} // 锁自动释放
// Arc: 原子引用计数(线程安全的 Rc)
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Result: {}", *counter.lock().unwrap());
Send 与 Sync
// Send: 可在线程间转移所有权
// Sync: 可从多线程安全访问
// 大多数类型是 Send + Sync
// Rc<T>: 不是 Send 或 Sync
// RefCell<T>: 不是 Sync
// Arc<T>: Send + Sync
// Mutex<T>: Send + Sync
// 手动实现 Send/Sync 是 unsafe 的
unsafe impl Send for MyType {}
异步编程
async/await
use tokio; // 需要在 Cargo.toml 添加依赖
// async 函数返回 Future
async fn hello_world() {
println!("hello, world!");
}
// await 等待 Future 完成
async fn learn_song() -> String {
// 模拟异步操作
String::from("learned!")
}
async fn sing_song(song: String) {
println!("Singing: {}", song);
}
async fn learn_and_sing() {
let song = learn_song().await;
sing_song(song).await;
}
// 运行时
#[tokio::main]
async fn main() {
learn_and_sing().await;
}
并发执行
use tokio;
async fn task1() {
println!("Task 1");
}
async fn task2() {
println!("Task 2");
}
#[tokio::main]
async fn main() {
// 并发执行
let (result1, result2) = tokio::join!(task1(), task2());
// 或使用 select! (竞争,第一个完成)
tokio::select! {
_ = task1() => println!("Task 1 finished first"),
_ = task2() => println!("Task 2 finished first"),
}
// spawn 任务
let handle = tokio::spawn(async {
// 异步工作
});
handle.await.unwrap();
}
Future trait
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
struct MyFuture;
impl Future for MyFuture {
type Output = i32;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
// 模拟工作
Poll::Ready(42)
}
}
模式匹配
基础模式
// 匹配字面值
let x = 1;
match x {
1 => println!("one"),
2 => println!("two"),
_ => println!("anything"),
}
// 匹配命名变量
let x = Some(5);
let y = 10;
match x {
Some(50) => println!("Got 50"),
Some(y) => println!("Matched, y = {:?}", y), // 遮蔽外部 y
_ => println!("Default case"),
}
// 多个模式
match x {
1 | 2 => println!("one or two"),
3 => println!("three"),
_ => println!("anything"),
}
// 范围匹配
match x {
1..=5 => println!("one through five"),
_ => println!("something else"),
}
let c = 'c';
match c {
'a'..='j' => println!("early ASCII letter"),
'k'..='z' => println!("late ASCII letter"),
_ => println!("something else"),
}
解构
// 解构结构体
struct Point {
x: i32,
y: i32,
}
let p = Point { x: 0, y: 7 };
match p {
Point { x, y: 0 } => println!("On the x axis at {}", x),
Point { x: 0, y } => println!("On the y axis at {}", y),
Point { x, y } => println!("On neither axis: ({}, {})", x, y),
}
// 解构枚举
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
let msg = Message::ChangeColor(0, 160, 255);
match msg {
Message::Quit => println!("Quit"),
Message::Move { x, y } => println!("Move to x:{}, y:{}", x, y),
Message::Write(text) => println!("Text: {}", text),
Message::ChangeColor(r, g, b) => println!("RGB({}, {}, {})", r, g, b),
}
// 解构嵌套
enum Color {
Rgb(i32, i32, i32),
Hsv(i32, i32, i32),
}
enum Message2 {
ChangeColor(Color),
}
let msg = Message2::ChangeColor(Color::Hsv(0, 160, 255));
match msg {
Message2::ChangeColor(Color::Rgb(r, g, b)) => {
println!("RGB: {}, {}, {}", r, g, b)
}
Message2::ChangeColor(Color::Hsv(h, s, v)) => {
println!("HSV: {}, {}, {}", h, s, v)
}
}
// 解构引用
let points = vec![
Point { x: 0, y: 0 },
Point { x: 1, y: 5 },
];
let sum_of_squares: i32 = points
.iter()
.map(|&Point { x, y }| x * x + y * y)
.sum();
高级模式
// 忽略值
let (x, _, z) = (1, 2, 3);
match some_value {
Some(_) => println!("got a Some"),
None => (),
}
// .. 忽略剩余值
struct Point3D {
x: i32,
y: i32,
z: i32,
}
let origin = Point3D { x: 0, y: 0, z: 0 };
match origin {
Point3D { x, .. } => println!("x is {}", x),
}
// 匹配守卫
let num = Some(4);
match num {
Some(x) if x < 5 => println!("less than five: {}", x),
Some(x) => println!("{}", x),
None => (),
}
// @ 绑定
enum Message3 {
Hello { id: i32 },
}
let msg = Message3::Hello { id: 5 };
match msg {
Message3::Hello { id: id_variable @ 3..=7 } => {
println!("Found an id in range: {}", id_variable)
}
Message3::Hello { id: 10..=12 } => {
println!("Found an id in another range")
}
Message3::Hello { id } => {
println!("Found some other id: {}", id)
}
}
宏系统
声明宏 (macrorules!)
// 基本宏
macro_rules! say_hello {
() => {
println!("Hello!");
};
}
say_hello!();
// 带参数
macro_rules! create_function {
($func_name:ident) => {
fn $func_name() {
println!("You called {:?}()", stringify!($func_name));
}
};
}
create_function!(foo);
foo();
// 重复模式
macro_rules! vec_of_strings {
($($x:expr),*) => {
{
let mut temp_vec = Vec::new();
$(
temp_vec.push($x.to_string());
)*
temp_vec
}
};
}
let v = vec_of_strings!("hello", "world");
// 指示符:
// - ident: 标识符
// - expr: 表达式
// - ty: 类型
// - pat: 模式
// - stmt: 语句
// - block: 代码块
// - item: 项(函数、结构体等)
// - meta: 属性内容
// - tt: token 树
过程宏
// Cargo.toml:
// [lib]
// proc-macro = true
//
// [dependencies]
// syn = "2.0"
// quote = "1.0"
use proc_macro::TokenStream;
use quote::quote;
use syn;
// 派生宏
#[proc_macro_derive(HelloMacro)]
pub fn hello_macro_derive(input: TokenStream) -> TokenStream {
let ast = syn::parse(input).unwrap();
impl_hello_macro(&ast)
}
fn impl_hello_macro(ast: &syn::DeriveInput) -> TokenStream {
let name = &ast.ident;
let gen = quote! {
impl HelloMacro for #name {
fn hello_macro() {
println!("Hello, Macro! My name is {}!", stringify!(#name));
}
}
};
gen.into()
}
// 使用:
#[derive(HelloMacro)]
struct Pancakes;
Pancakes::hello_macro();
// 属性宏
#[proc_macro_attribute]
pub fn route(attr: TokenStream, item: TokenStream) -> TokenStream {
// 实现路由逻辑
}
// 使用: #[route(GET, "/")]
// 函数式宏
#[proc_macro]
pub fn sql(input: TokenStream) -> TokenStream {
// 实现 SQL DSL
}
// 使用: let query = sql!(SELECT * FROM users);
不安全 Rust
unsafe 关键字
// 五种 unsafe 超能力:
// 1. 解引用裸指针
// 2. 调用 unsafe 函数或方法
// 3. 访问或修改可变静态变量
// 4. 实现 unsafe trait
// 5. 访问 union 的字段
// 裸指针
let mut num = 5;
let r1 = &num as *const i32; // 不可变裸指针
let r2 = &mut num as *mut i32; // 可变裸指针
unsafe {
println!("r1 is: {}", *r1);
println!("r2 is: {}", *r2);
}
// unsafe 函数
unsafe fn dangerous() {
// 危险操作
}
unsafe {
dangerous();
}
// 创建 unsafe 代码的安全抽象
fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
let len = slice.len();
let ptr = slice.as_mut_ptr();
assert!(mid <= len);
unsafe {
(
std::slice::from_raw_parts_mut(ptr, mid),
std::slice::from_raw_parts_mut(ptr.add(mid), len - mid),
)
}
}
// 外部函数接口 (FFI)
extern "C" {
fn abs(input: i32) -> i32;
}
unsafe {
println!("Absolute value of -3 according to C: {}", abs(-3));
}
// 从其他语言调用 Rust
#[no_mangle]
pub extern "C" fn call_from_c() {
println!("Just called a Rust function from C!");
}
// 静态变量
static HELLO_WORLD: &str = "Hello, world!";
static mut COUNTER: u32 = 0;
fn add_to_count(inc: u32) {
unsafe {
COUNTER += inc;
}
}
// unsafe trait
unsafe trait Foo {
// 方法
}
unsafe impl Foo for i32 {
// 实现
}
高级特性
关联类型
pub trait Iterator {
type Item; // 关联类型
fn next(&mut self) -> Option<Self::Item>;
}
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
// 实现
}
}
// vs 泛型: 关联类型每个类型只能实现一次
运算符重载
use std::ops::Add;
#[derive(Debug, PartialEq)]
struct Point {
x: i32,
y: i32,
}
impl Add for Point {
type Output = Point;
fn add(self, other: Point) -> Point {
Point {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
let p1 = Point { x: 1, y: 0 };
let p2 = Point { x: 2, y: 3 };
let p3 = p1 + p2;
// 其他可重载运算符: Sub, Mul, Div, Rem,
// Neg, Not, BitAnd, BitOr, BitXor, Shl, Shr,
// Index, IndexMut, Deref, DerefMut
完全限定语法
trait Pilot {
fn fly(&self);
}
trait Wizard {
fn fly(&self);
}
struct Human;
impl Pilot for Human {
fn fly(&self) {
println!("This is your captain speaking.");
}
}
impl Wizard for Human {
fn fly(&self) {
println!("Up!");
}
}
impl Human {
fn fly(&self) {
println!("*waving arms furiously*");
}
}
let person = Human;
person.fly(); // 调用 Human::fly
Pilot::fly(&person); // 调用 Pilot::fly
Wizard::fly(&person); // 调用 Wizard::fly
// 关联函数的完全限定语法
trait Animal {
fn baby_name() -> String;
}
struct Dog;
impl Dog {
fn baby_name() -> String {
String::from("puppy")
}
}
impl Animal for Dog {
fn baby_name() -> String {
String::from("puppy")
}
}
println!("{}", Dog::baby_name()); // "puppy"
println!("{}", <Dog as Animal>::baby_name()); // "puppy"
Supertraits
use std::fmt;
trait OutlinePrint: fmt::Display {
fn outline_print(&self) {
let output = self.to_string();
let len = output.len();
println!("{}", "*".repeat(len + 4));
println!("*{}*", " ".repeat(len + 2));
println!("* {} *", output);
println!("*{}*", " ".repeat(len + 2));
println!("{}", "*".repeat(len + 4));
}
}
// 实现 OutlinePrint 必须先实现 Display
newtype 模式
// 为外部类型实现外部 trait
use std::fmt;
struct Wrapper(Vec<String>);
impl fmt::Display for Wrapper {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[{}]", self.0.join(", "))
}
}
let w = Wrapper(vec![String::from("hello"), String::from("world")]);
println!("w = {}", w);
类型别名
type Kilometers = i32; // 类型别名
let x: i32 = 5;
let y: Kilometers = 5;
println!("{} + {} = {}", x, y, x + y); // 完全等价
// 减少重复
type Thunk = Box<dyn Fn() + Send + 'static>;
let f: Thunk = Box::new(|| println!("hi"));
// 在 Result 中使用
type Result<T> = std::result::Result<T, std::io::Error>;
Never 类型
// ! 表示永不返回
fn bar() -> ! {
panic!("This function never returns");
}
// continue 的类型是 !
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue, // ! 类型可强制转换为任何类型
};
动态大小类型 (DST)
// str 是 DST: 编译时不知道大小
let s1: &str = "Hello"; // 必须用引用
// trait 对象是 DST
let v: &dyn ToString = &5;
// Sized trait: 编译时已知大小
fn generic<T>(t: T) {
// T 默认有 Sized 约束
}
// 等价于:
fn generic<T: Sized>(t: T) {}
// 移除 Sized 约束:
fn generic<T: ?Sized>(t: &T) {
// T 可以是 DST,但必须用引用
}
测试
单元测试
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
#[test]
fn another() {
assert!(true);
assert_ne!(1, 2);
}
#[test]
#[should_panic]
fn it_panics() {
panic!("Make this test fail");
}
#[test]
#[should_panic(expected = "less than or equal to 100")]
fn greater_than_100() {
Guess::new(200);
}
#[test]
fn it_works_result() -> Result<(), String> {
if 2 + 2 == 4 {
Ok(())
} else {
Err(String::from("two plus two does not equal four"))
}
}
#[test]
#[ignore] // 除非 --ignored,否则跳过
fn expensive_test() {
// 耗时测试
}
}
集成测试
// tests/integration_test.rs
use my_crate;
#[test]
fn it_adds_two() {
assert_eq!(4, my_crate::add_two(2));
}
// tests/common/mod.rs
pub fn setup() {
// 测试辅助代码
}
// 运行测试
// cargo test # 所有测试
// cargo test test_name # 特定测试
// cargo test --test integration_test # 特定集成测试文件
// cargo test -- --test-threads=1 # 串行运行
// cargo test -- --show-output # 显示成功测试的输出
基准测试 (需 nightly)
#![feature(test)]
extern crate test;
#[cfg(test)]
mod benches {
use super::*;
use test::Bencher;
#[bench]
fn bench_add_two(b: &mut Bencher) {
b.iter(|| add_two(2));
}
}
文档
文档注释
/// 为函数或类型生成文档
///
/// # Examples
///
/// ```
/// let result = my_crate::add_one(5);
/// assert_eq!(result, 6);
/// ```
///
/// # Panics
///
/// 当 x 溢出时 panic
///
/// # Errors
///
/// 返回 Err 当 ...
///
/// # Safety
///
/// 调用者必须确保 ...
pub fn add_one(x: i32) -> i32 {
x + 1
}
//! 为包含项(模块、crate)生成文档
//!
//! # 我的 Crate
//!
//! 这个 crate 提供 ...
// cargo doc --open # 生成并打开文档
Cargo 高级特性
Cargo.toml 配置
[package] name = "my_project" version = "0.1.0" edition = "2021" authors = ["Your Name <you@example.com>"] description = "A short description" license = "MIT OR Apache-2.0" repository = "https://github.com/username/repo" keywords = ["cli", "example"] categories = ["command-line-utilities"] [dependencies] serde = { version = "1.0", features = ["derive"] } tokio = { version = "1.0", features = ["full"] } rand = "0.8" [dev-dependencies] criterion = "0.5" [build-dependencies] cc = "1.0" [profile.release] opt-level = 3 lto = true # Link Time Optimization codegen-units = 1 # 更好的优化,但编译慢 [profile.dev] opt-level = 0 # Workspace [workspace] members = [ "crate1", "crate2", ]
Feature Flags
[features] default = ["std"] std = [] serde_support = ["serde", "serde_derive"] [dependencies] serde = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true }
#[cfg(feature = "serde_support")]
use serde::{Serialize, Deserialize};
#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))]
pub struct MyStruct {
data: String,
}
// cargo build --features "serde_support"
// cargo build --all-features
// cargo build --no-default-features
条件编译
#[cfg(target_os = "linux")]
fn platform_specific() {
println!("Linux!");
}
#[cfg(target_os = "windows")]
fn platform_specific() {
println!("Windows!");
}
#[cfg(all(unix, target_pointer_width = "64"))]
fn unix_64bit() {}
#[cfg(any(target_os = "linux", target_os = "macos"))]
fn unix_like() {}
#[cfg(not(test))]
fn production_only() {}
最佳实践与 Tips
代码组织
// src/lib.rs
pub mod models; // src/models.rs 或 src/models/mod.rs
pub mod utils;
pub use models::User; // 重导出
// src/models.rs
pub struct User {
pub name: String,
}
// 私有性默认原则
mod my_mod {
pub struct PublicStruct {
pub public_field: i32,
private_field: i32, // 私有
}
impl PublicStruct {
pub fn new() -> PublicStruct {
PublicStruct {
public_field: 0,
private_field: 0,
}
}
}
}
错误处理最佳实践
use thiserror::Error; // 推荐使用 thiserror
#[derive(Error, Debug)]
pub enum MyError {
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("Parse error: {0}")]
Parse(#[from] std::num::ParseIntError),
#[error("Custom error: {msg}")]
Custom { msg: String },
}
pub type Result<T> = std::result::Result<T, MyError>;
// 使用 anyhow 处理应用级错误
use anyhow::{Context, Result};
fn read_config() -> Result<Config> {
let contents = std::fs::read_to_string("config.toml")
.context("Failed to read config file")?;
let config: Config = toml::from_str(&contents)
.context("Failed to parse config")?;
Ok(config)
}
性能优化技巧
// 1. 避免不必要的克隆
fn process(data: &str) { // 用借用而非 String
// ...
}
// 2. 使用 Cow 延迟克隆
use std::borrow::Cow;
fn process<'a>(input: &'a str) -> Cow<'a, str> {
if input.contains("special") {
Cow::Owned(input.replace("special", "normal"))
} else {
Cow::Borrowed(input)
}
}
// 3. 预分配容量
let mut vec = Vec::with_capacity(100);
// 4. 使用迭代器而非循环
let sum: i32 = (1..100)
.filter(|x| x % 2 == 0)
.map(|x| x * x)
.sum();
// 5. 使用 &[T] 而非 &Vec<T>
fn process_items(items: &[Item]) { // 更通用
// ...
}
// 6. SmallVec: 小数据栈分配
use smallvec::{SmallVec, smallvec};
let mut vec: SmallVec<[u8; 16]> = smallvec![1, 2, 3];
// 7. 使用 unsafe 优化关键路径(谨慎!)
// 但先用 Cargo.toml profile 优化
常用设计模式
// 1. Newtype 模式
struct UserId(u64);
struct UserName(String);
// 2. Builder 模式
pub struct Config {
host: String,
port: u16,
}
pub struct ConfigBuilder {
host: Option<String>,
port: Option<u16>,
}
impl ConfigBuilder {
pub fn new() -> Self {
Self { host: None, port: None }
}
pub fn host(mut self, host: String) -> Self {
self.host = Some(host);
self
}
pub fn port(mut self, port: u16) -> Self {
self.port = Some(port);
self
}
pub fn build(self) -> Result<Config, &'static str> {
Ok(Config {
host: self.host.ok_or("host required")?,
port: self.port.unwrap_or(8080),
})
}
}
// 使用: derive_builder crate 自动生成
// 3. RAII (资源获取即初始化)
struct File {
handle: std::fs::File,
}
impl File {
fn new(path: &str) -> std::io::Result<Self> {
let handle = std::fs::File::open(path)?;
Ok(File { handle })
}
}
impl Drop for File {
fn drop(&mut self) {
// 自动清理资源
println!("Closing file");
}
}
// 4. 类型状态模式
struct Locked;
struct Unlocked;
struct Door<State> {
_state: PhantomData<State>,
}
impl Door<Locked> {
fn new() -> Self {
Door { _state: PhantomData }
}
fn unlock(self) -> Door<Unlocked> {
Door { _state: PhantomData }
}
}
impl Door<Unlocked> {
fn open(&self) {
println!("Door opened");
}
fn lock(self) -> Door<Locked> {
Door { _state: PhantomData }
}
}
// 5. 策略模式 (使用 trait objects)
trait CompressionStrategy {
fn compress(&self, data: &[u8]) -> Vec<u8>;
}
struct GzipCompression;
impl CompressionStrategy for GzipCompression {
fn compress(&self, data: &[u8]) -> Vec<u8> {
// gzip 实现
vec![]
}
}
struct Compressor {
strategy: Box<dyn CompressionStrategy>,
}
impl Compressor {
fn compress(&self, data: &[u8]) -> Vec<u8> {
self.strategy.compress(data)
}
}
内存布局优化
// 字段排序影响大小
struct Bad {
a: u8, // 1 byte + 7 padding
b: u64, // 8 bytes
c: u8, // 1 byte + 7 padding
} // 总共: 24 bytes
struct Good {
b: u64, // 8 bytes
a: u8, // 1 byte
c: u8, // 1 byte + 6 padding
} // 总共: 16 bytes
// 使用 #[repr(C)] 固定布局
#[repr(C)]
struct CLayout {
x: u8,
y: u32,
}
// 使用 #[repr(packed)] 移除 padding (小心对齐!)
#[repr(packed)]
struct Packed {
x: u8,
y: u32,
}
常用 Crate 推荐
[dependencies] # 序列化 serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" toml = "0.8" # 异步运行时 tokio = { version = "1.0", features = ["full"] } async-std = "1.12" # HTTP 客户端 reqwest = { version = "0.11", features = ["json"] } hyper = "0.14" # Web 框架 axum = "0.7" actix-web = "4.4" rocket = "0.5" # CLI clap = { version = "4.0", features = ["derive"] } structopt = "0.3" # 错误处理 anyhow = "1.0" thiserror = "1.0" # 日志 log = "0.4" env_logger = "0.11" tracing = "0.1" # 测试 proptest = "1.0" # 属性测试 mockall = "0.12" # Mock criterion = "0.5" # 基准测试 # 数据库 sqlx = { version = "0.7", features = ["runtime-tokio-native-tls", "postgres"] } diesel = { version = "2.1", features = ["postgres"] } # 实用工具 itertools = "0.12" rayon = "1.8" # 数据并行 once_cell = "1.19" # 延迟初始化 lazy_static = "1.4" regex = "1.10" chrono = "0.4" # 日期时间 uuid = "1.6"
Clippy 常见建议
// 使用 if let 代替 match
// Bad
match some_option {
Some(x) => println!("{}", x),
None => {},
}
// Good
if let Some(x) = some_option {
println!("{}", x);
}
// 使用 .copied() 或 .cloned()
// Bad
let v: Vec<i32> = vec![1, 2, 3];
let x = v.iter().map(|&x| x).collect::<Vec<_>>();
// Good
let x = v.iter().copied().collect::<Vec<_>>();
// 避免不必要的返回
// Bad
fn add(a: i32, b: i32) -> i32 {
return a + b;
}
// Good
fn add(a: i32, b: i32) -> i32 {
a + b
}
// 使用 matches! 宏
// Bad
match value {
Some(1) | Some(2) => true,
_ => false,
}
// Good
matches!(value, Some(1) | Some(2))
// 使用 ..= 代替 ...
// Bad (已废弃)
match x {
0...10 => {},
_ => {},
}
// Good
match x {
0..=10 => {},
_ => {},
}
生命周期技巧
// 1. 生命周期省略
fn first_word(s: &str) -> &str { // 编译器自动推断
&s[..1]
}
// 2. 'static 生命周期
const GREETING: &'static str = "Hello";
fn get_static() -> &'static str {
"static string"
}
// 3. 结构体自引用 (使用 Pin)
use std::pin::Pin;
struct SelfReferential {
data: String,
ptr: *const String,
}
// 更好的方式: 使用 rental 或 ouroboros crate
// 4. 高阶生命周期 (HRTB)
fn call_with_ref<F>(f: F)
where
F: for<'a> Fn(&'a str),
{
f("hello");
}
并发模式
use std::sync::mpsc;
use std::thread;
use std::sync::{Arc, Mutex};
// 1. 工作线程池
struct ThreadPool {
workers: Vec<Worker>,
sender: mpsc::Sender<Job>,
}
type Job = Box<dyn FnOnce() + Send + 'static>;
impl ThreadPool {
fn new(size: usize) -> ThreadPool {
let (sender, receiver) = mpsc::channel();
let receiver = Arc::new(Mutex::new(receiver));
let mut workers = Vec::with_capacity(size);
for id in 0..size {
workers.push(Worker::new(id, Arc::clone(&receiver)));
}
ThreadPool { workers, sender }
}
fn execute<F>(&self, f: F)
where
F: FnOnce() + Send + 'static,
{
let job = Box::new(f);
self.sender.send(job).unwrap();
}
}
struct Worker {
id: usize,
thread: thread::JoinHandle<()>,
}
impl Worker {
fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Job>>>) -> Worker {
let thread = thread::spawn(move || loop {
let job = receiver.lock().unwrap().recv().unwrap();
job();
});
Worker { id, thread }
}
}
// 2. Actor 模式
struct Actor {
receiver: mpsc::Receiver<Message>,
}
enum Message {
NewJob(String),
Terminate,
}
impl Actor {
fn run(&mut self) {
while let Ok(msg) = self.receiver.recv() {
match msg {
Message::NewJob(job) => self.handle_job(job),
Message::Terminate => break,
}
}
}
fn handle_job(&self, job: String) {
println!("Processing: {}", job);
}
}
测试技巧
// 1. 表格驱动测试
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
let test_cases = vec![
(1, 2, 3),
(0, 0, 0),
(-1, 1, 0),
];
for (a, b, expected) in test_cases {
assert_eq!(add(a, b), expected);
}
}
// 2. 使用 test fixtures
struct TestFixture {
db: Database,
}
impl TestFixture {
fn new() -> Self {
TestFixture {
db: Database::new_test(),
}
}
}
impl Drop for TestFixture {
fn drop(&mut self) {
self.db.cleanup();
}
}
#[test]
fn test_with_fixture() {
let fixture = TestFixture::new();
// 测试使用 fixture.db
}
// 3. 属性测试
use proptest::prelude::*;
proptest! {
#[test]
fn test_reverse_reverse(s: String) {
let reversed: String = s.chars().rev().collect();
let double_reversed: String = reversed.chars().rev().collect();
prop_assert_eq!(s, double_reversed);
}
}
}
编译时计算
const fn
const fn fibonacci(n: u32) -> u32 {
match n {
0 => 0,
1 => 1,
_ => fibonacci(n - 1) + fibonacci(n - 2),
}
}
const FIB_10: u32 = fibonacci(10); // 编译时计算
// const fn 限制:
// - 不能调用非 const fn
// - 不能有循环 (可用递归)
// - 某些操作受限
常量泛型
// 数组长度泛型化
fn sum_array<const N: usize>(arr: [i32; N]) -> i32 {
arr.iter().sum()
}
let arr = [1, 2, 3, 4, 5];
let total = sum_array(arr);
// 编译时保证大小
struct Matrix<T, const ROWS: usize, const COLS: usize> {
data: [[T; COLS]; ROWS],
}
impl<T, const ROWS: usize, const COLS: usize> Matrix<T, ROWS, COLS> {
fn transpose<const NEW_ROWS: usize, const NEW_COLS: usize>(
self,
) -> Matrix<T, NEW_ROWS, NEW_COLS>
where
[(); ROWS]: Sized,
[(); COLS]: Sized,
{
// 实现
todo!()
}
}
内联汇编
#![feature(asm)]
use std::arch::asm;
unsafe {
let mut x: u64 = 10;
asm!(
"add {0}, {1}",
inout(reg) x,
in(reg) 5,
);
println!("Result: {}", x); // 15
}
// x86_64 示例
#[cfg(target_arch = "x86_64")]
unsafe fn cpuid() -> u32 {
let mut eax: u32;
asm!(
"cpuid",
inout("eax") 0 => eax,
out("ebx") _,
out("ecx") _,
out("edx") _,
);
eax
}
模块化与发布
模块系统最佳实践
// src/lib.rs - 库根
pub mod config;
pub mod error;
pub use config::Config;
pub use error::{Error, Result};
// 预导出常用项
pub mod prelude {
pub use crate::Config;
pub use crate::Error;
pub use crate::Result;
}
// src/config.rs
use crate::error::Result;
#[derive(Debug, Clone)]
pub struct Config {
// ...
}
impl Config {
pub fn load() -> Result<Self> {
// ...
}
}
// 使用者:
use my_crate::prelude::*;
发布到 crates.io
# 1. 登录 cargo login <your-token> # 2. 检查包 cargo package # 3. 发布 cargo publish # 4. 撤回版本 (不删除,仅标记) cargo yank --vers 1.0.1 # 5. 取消撤回 cargo yank --vers 1.0.1 --undo
语义化版本
# 主版本.次版本.补丁版本 version = "1.2.3" # 依赖版本指定 [dependencies] some_crate = "1.2.3" # 精确版本 some_crate = "^1.2.3" # >=1.2.3, <2.0.0 (默认) some_crate = "~1.2.3" # >=1.2.3, <1.3.0 some_crate = "1.2.*" # >=1.2.0, <1.3.0 some_crate = ">=1.2, <1.5" some_crate = { git = "https://github.com/user/repo" } some_crate = { path = "../local-crate" }
调试技巧
dbg! 宏
fn factorial(n: u32) -> u32 {
if dbg!(n <= 1) {
dbg!(1)
} else {
dbg!(n * factorial(n - 1))
}
}
let result = dbg!(factorial(4));
// 输出:
// [src/main.rs:3] n <= 1 = false
// [src/main.rs:3] n <= 1 = false
// [src/main.rs:3] n <= 1 = false
// [src/main.rs:3] n <= 1 = true
// [src/main.rs:4] 1 = 1
// [src/main.rs:6] n * factorial(n - 1) = 2
// ...
日志
use log::{info, warn, error, debug, trace};
fn main() {
env_logger::init();
trace!("Trace message");
debug!("Debug message");
info!("Info message");
warn!("Warning message");
error!("Error message");
}
// 运行: RUST_LOG=debug cargo run
性能分析
# 使用 perf cargo build --release perf record --call-graph=dwarf ./target/release/myapp perf report # 使用 flamegraph cargo install flamegraph cargo flamegraph # 使用 valgrind cargo build valgrind --tool=callgrind ./target/debug/myapp kcachegrind callgrind.out.*
跨平台编译
目标平台
# 列出所有目标 rustup target list # 添加目标 rustup target add x86_64-pc-windows-gnu rustup target add aarch64-unknown-linux-gnu rustup target add wasm32-unknown-unknown # 交叉编译 cargo build --target x86_64-pc-windows-gnu
条件编译示例
#[cfg(target_os = "linux")]
mod linux_specific {
pub fn platform_name() -> &'static str {
"Linux"
}
}
#[cfg(target_os = "windows")]
mod windows_specific {
pub fn platform_name() -> &'static str {
"Windows"
}
}
#[cfg(target_os = "macos")]
mod macos_specific {
pub fn platform_name() -> &'static str {
"macOS"
}
}
#[cfg(target_family = "unix")]
fn unix_only() {
println!("This is Unix-like");
}
#[cfg(target_pointer_width = "64")]
fn only_64bit() {
println!("64-bit platform");
}
WebAssembly
基础配置
[dependencies] wasm-bindgen = "0.2" [lib] crate-type = ["cdylib"]
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn greet(name: &str) -> String {
format!("Hello, {}!", name)
}
#[wasm_bindgen]
pub struct Counter {
count: i32,
}
#[wasm_bindgen]
impl Counter {
#[wasm_bindgen(constructor)]
pub fn new() -> Counter {
Counter { count: 0 }
}
pub fn increment(&mut self) {
self.count += 1;
}
pub fn get_count(&self) -> i32 {
self.count
}
}
// 编译:
// wasm-pack build --target web
嵌入式 Rust
nostd 环境
#![no_std]
#![no_main]
use panic_halt as _; // panic handler
use cortex_m_rt::entry;
#[entry]
fn main() -> ! {
// 嵌入式主循环
loop {
// ...
}
}
最后的建议
学习路径
- 理解所有权系统
- 掌握生命周期
- 熟悉 trait 系统
- 学习并发模式
- 探索异步编程
- 深入 unsafe 和 FFI
实践建议
- 从小项目开始: CLI 工具、API 客户端
- 阅读优秀 crate 源码: serde, tokio, clap
- 参与开源项目
- 善用 Rust 社区: Reddit, Discord, 论坛
- 坚持"如果编译通过,大概率正确"的信念
资源推荐
- 官方文档: https://doc.rust-lang.org/
- Rust by Example: https://doc.rust-lang.org/rust-by-example/
- The Rust Book: 必读圣经
- Async Book: 异步编程指南
- Nomicon: unsafe Rust 指南
- Rust Quiz: 挑战题集
常见陷阱
- 过度使用 clone() 和 unwrap()
- 与借用检查器对抗而非协作
- 忽视生命周期注解的含义
- 在不需要时使用 Arc<Mutex<T>>
- 过早优化
心态调整
Rust 学习曲线陡峭但值得:
- 初期: 与编译器搏斗
- 中期: 理解编译器意图
- 后期: 感激编译器保护
编译器是你的朋友,不是敌人!
Comments:
Email questions, comments, and corrections to hi@smartisan.dev.
Submissions may appear publicly on this website, unless requested otherwise in your email.