rust-systems-programming
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseRust Systems Programming
Rust系统编程
A comprehensive skill for building high-performance, memory-safe systems software using Rust. This skill covers ownership, borrowing, concurrency, async programming, unsafe code, FFI, and performance optimization for systems-level development.
这是一份使用Rust构建高性能、内存安全系统软件的全面指南,涵盖系统级开发中的所有权、借用、并发、异步编程、不安全代码、FFI(外部函数接口)及性能优化等内容。
When to Use This Skill
何时使用本指南
Use this skill when:
- Building systems software requiring memory safety without garbage collection
- Developing high-performance applications with zero-cost abstractions
- Writing concurrent or parallel programs with data race prevention
- Creating async/await applications for I/O-bound workloads (web servers, databases)
- Working with low-level code, FFI, or hardware interfaces
- Replacing C/C++ code with safer alternatives
- Building command-line tools, network services, or embedded systems
- Optimizing performance-critical sections of applications
- Creating libraries that guarantee memory safety at compile time
- Developing WebAssembly modules for near-native performance
在以下场景中使用本指南:
- 构建无需垃圾回收且要求内存安全的系统软件
- 开发具备零成本抽象的高性能应用
- 编写可防止数据竞争的并发或并行程序
- 为I/O密集型工作负载(Web服务器、数据库)创建async/await应用
- 处理底层代码、FFI或硬件接口
- 使用更安全的替代方案替换C/C++代码
- 构建命令行工具、网络服务或嵌入式系统
- 优化应用中性能关键的代码段
- 创建在编译期保证内存安全的库
- 开发具备接近原生性能的WebAssembly模块
Core Concepts
核心概念
The Ownership Model
所有权模型
Rust's ownership system is the foundation of its memory safety guarantees:
Ownership Rules:
- Each value in Rust has exactly one owner
- When the owner goes out of scope, the value is dropped
- Ownership can be transferred (moved) to new owners
Move Semantics:
rust
struct MyStruct { s: u32 }
fn main() {
let mut x = MyStruct{ s: 5u32 };
let y = x; // Ownership moved from x to y
// x.s = 6; // ERROR: x is no longer valid
// println!("{}", x.s); // ERROR: cannot use x after move
}When a type doesn't implement , assignment moves ownership rather than copying. This prevents double-free errors and use-after-move bugs at compile time.
CopyFor Copy Types:
rust
let x = 5; // i32 implements Copy
let y = x; // x is copied, not moved
println!("{}", x); // OK: x is still validRust的所有权系统是其内存安全保障的基础:
所有权规则:
- Rust中的每个值恰好有一个所有者
- 当所有者离开作用域时,对应的值会被销毁
- 所有权可以转移(移动)给新的所有者
移动语义:
rust
struct MyStruct { s: u32 }
fn main() {
let mut x = MyStruct{ s: 5u32 };
let y = x; // 所有权从x移动到y
// x.s = 6; // 错误:x不再有效
// println!("{}", x.s); // 错误:移动后无法使用x
}当类型未实现时,赋值操作会转移所有权而非复制。这在编译期就防止了双重释放错误和移动后使用的bug。
Copy对于实现Copy的类型:
rust
let x = 5; // i32实现了Copy
let y = x; // x被复制,而非移动
println!("{}", x); // 正常:x仍然有效Borrowing and References
借用与引用
Borrowing allows temporary access to data without taking ownership:
Immutable Borrowing:
rust
fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1); // Borrow s1 immutably
println!("The length of '{}' is {}.", s1, len); // s1 still valid
}
fn calculate_length(s: &String) -> usize {
s.len() // Can read but not modify
}Mutable Borrowing:
Rust enforces exclusive mutable access to prevent data races:
rust
fn main() {
let mut value = 3;
let borrow = &mut value; // Mutable borrow
*borrow += 1;
println!("{}", borrow); // 4
// value is accessible again after borrow ends
}Borrowing Rules:
- You can have either one mutable reference OR any number of immutable references
- References must always be valid (no dangling pointers)
- Mutable and immutable borrows cannot coexist
Common Borrowing Error:
rust
fn main() {
let mut value = 3;
// Create a mutable borrow of `value`.
let borrow = &mut value;
let _sum = value + 1; // ERROR: cannot use `value` because
// it was mutably borrowed
println!("{}", borrow);
}借用允许临时访问数据而无需获取所有权:
不可变借用:
rust
fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1); // 不可变借用s1
println!("'{}'的长度是{}", s1, len); // s1仍然有效
}
fn calculate_length(s: &String) -> usize {
s.len() // 仅可读取,不可修改
}可变借用:
Rust强制要求独占可变访问以防止数据竞争:
rust
fn main() {
let mut value = 3;
let borrow = &mut value; // 可变借用
*borrow += 1;
println!("{}", borrow); // 4
// 借用结束后,value可再次被访问
}借用规则:
- 你可以拥有一个可变引用,或者任意数量的不可变引用,但二者不能同时存在
- 引用必须始终有效(无悬空指针)
- 可变借用与不可变借用不能共存
常见借用错误:
rust
fn main() {
let mut value = 3;
// 创建`value`的可变借用
let borrow = &mut value;
let _sum = value + 1; // 错误:无法使用`value`,因为它已被可变借用
println!("{}", borrow);
}Lifetimes
生命周期
Lifetimes ensure references are always valid:
rust
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}The lifetime parameter tells the compiler that the returned reference will be valid as long as both input references are valid.
'a生命周期确保引用始终有效:
rust
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}'aOwnership Patterns for Sharing
用于共享的所有权模式
Rc (Reference Counted) for Single-threaded Shared Ownership:
rust
use std::cell::RefCell;
use std::rc::Rc;
struct MyStruct { s: u32 }
fn main() {
let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 }));
let y = x.clone(); // Increment reference count
x.borrow_mut().s = 6; // Interior mutability via RefCell
println!("{}", x.borrow().s);
}Rc<T>RefCell<T>Arc (Atomic Reference Counted) for Thread-safe Sharing:
rust
use std::sync::Arc;
use std::thread;
struct FancyNum {
num: u8,
}
fn main() {
let fancy_ref1 = Arc::new(FancyNum { num: 5 });
let fancy_ref2 = fancy_ref1.clone();
let x = thread::spawn(move || {
// `fancy_ref1` can be moved and has a `'static` lifetime
println!("child thread: {}", fancy_ref1.num);
});
x.join().expect("child thread should finish");
println!("main thread: {}", fancy_ref2.num);
}Arc<T>Rc<T>Rc(引用计数):单线程下的共享所有权
rust
use std::cell::RefCell;
use std::rc::Rc;
struct MyStruct { s: u32 }
fn main() {
let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 }));
let y = x.clone(); // 增加引用计数
x.borrow_mut().s = 6; // 通过RefCell实现内部可变性
println!("{}", x.borrow().s);
}Rc<T>RefCell<T>Arc(原子引用计数):线程安全的共享
rust
use std::sync::Arc;
use std::thread;
struct FancyNum {
num: u8,
}
fn main() {
let fancy_ref1 = Arc::new(FancyNum { num: 5 });
let fancy_ref2 = fancy_ref1.clone();
let x = thread::spawn(move || {
// `fancy_ref1`可被移动,且具有`'static`生命周期
println!("child thread: {}", fancy_ref1.num);
});
x.join().expect("child thread should finish");
println!("main thread: {}", fancy_ref2.num);
}Arc<T>Rc<T>Box for Heap Allocation
Box:堆内存分配
rust
Box<T>Box<T>T- Recursive types with known size
- Large values that should not be copied on the stack
- Trait objects with dynamic dispatch
rust
Box<T>Box<T>T- 大小已知的递归类型
- 不应在栈上复制的大型值
- 具备动态分发的 trait 对象
Concurrency Patterns
并发模式
Threads and Message Passing
线程与消息传递
Rust prevents data races at compile time through its ownership system:
rust
use std::thread;
use std::sync::mpsc;
fn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
tx.send("Hello from thread").unwrap();
});
let message = rx.recv().unwrap();
println!("{}", message);
}Rust通过其所有权系统在编译期防止数据竞争:
rust
use std::thread;
use std::sync::mpsc;
fn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
tx.send("Hello from thread").unwrap();
});
let message = rx.recv().unwrap();
println!("{}", message);
}Shared State with Mutex
使用Mutex实现共享状态
rust
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);
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());
}Key Concurrency Types:
- : Mutual exclusion lock for shared mutable state
Mutex<T> - : Reader-writer lock allowing multiple readers or one writer
RwLock<T> - : Atomic reference counting for thread-safe sharing
Arc<T> - : Multi-producer, single-consumer channels
mpsc
rust
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);
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());
}核心并发类型:
- :用于共享可变状态的互斥锁
Mutex<T> - :允许多个读取者或一个写入者的读写锁
RwLock<T> - :用于线程安全共享的原子引用计数
Arc<T> - :多生产者、单消费者通道
mpsc
Data Race Prevention
数据竞争预防
ThreadSanitizer Example:
rust
static mut A: usize = 0;
fn main() {
let t = std::thread::spawn(|| {
unsafe { A += 1 };
});
unsafe { A += 1 };
t.join().unwrap();
}This code has a data race. ThreadSanitizer (enabled with ) detects concurrent access to static mutable data:
RUSTFLAGS=-Zsanitizer=threadWARNING: ThreadSanitizer: data race (pid=10574)
Read of size 8 at 0x5632dfe3d030 by thread T1:
Previous write of size 8 at 0x5632dfe3d030 by main thread:ThreadSanitizer示例:
rust
static mut A: usize = 0;
fn main() {
let t = std::thread::spawn(|| {
unsafe { A += 1 };
});
unsafe { A += 1 };
t.join().unwrap();
}这段代码存在数据竞争。ThreadSanitizer(通过启用)可检测到对静态可变数据的并发访问:
RUSTFLAGS=-Zsanitizer=threadWARNING: ThreadSanitizer: data race (pid=10574)
Read of size 8 at 0x5632dfe3d030 by thread T1:
Previous write of size 8 at 0x5632dfe3d030 by main thread:Async Programming
异步编程
Async/Await Basics
Async/Await基础
Async programming in Rust allows concurrent I/O without blocking threads:
rust
async fn foo(n: usize) {
if n > 0 {
Box::pin(foo(n - 1)).await;
}
}Recursive async functions require to give the future a known size.
Box::pin()Rust中的异步编程允许在不阻塞线程的情况下处理并发I/O:
rust
async fn foo(n: usize) {
if n > 0 {
Box::pin(foo(n - 1)).await;
}
}递归异步函数需要来为future提供已知大小。
Box::pin()Async Closures
异步闭包
Async Closure with Move Semantics:
rust
fn force_fnonce<T: async FnOnce()>(t: T) -> T { t }
let x = String::new();
let c = force_fnonce(async move || {
println!("{x}");
});When constrained to , the closure captures by move to ensure proper ownership.
AsyncFnOnceAsync Closure Borrowing:
rust
let x = &1i32; // Lifetime '1
let c = async move || {
println!("{:?}", *x);
// Even though the closure moves x, we're only capturing *x,
// so the inner coroutine can reborrow the data for its original lifetime.
};Mutable Borrowing in Async Closures:
rust
let mut x = 1i32;
let c = async || {
x = 1;
// The parent borrows `x` mutably.
// When we call `c()`, we implicitly autoref for `AsyncFnMut::async_call_mut`.
// The inner coroutine captures with the lifetime of the coroutine-closure.
};具备移动语义的异步闭包:
rust
fn force_fnonce<T: async FnOnce()>(t: T) -> T { t }
let x = String::new();
let c = force_fnonce(async move || {
println!("{x}");
});当约束为时,闭包会通过移动捕获变量以确保正确的所有权。
AsyncFnOnce异步闭包的借用:
rust
let x = &1i32; // 生命周期'1
let c = async move || {
println!("{:?}", *x);
// 尽管闭包移动了x,但我们仅捕获了*x,因此内部协程可以为其原始生命周期重新借用数据。
};异步闭包中的可变借用:
rust
let mut x = 1i32;
let c = async || {
x = 1;
// 父级可变借用`x`
// 当我们调用`c()`时,会隐式自动引用以调用`AsyncFnMut::async_call_mut`
// 内部协程以协程闭包的生命周期捕获数据。
};Common Async Errors
常见异步错误
E0373: Async block capturing short-lived variable:
rust
use std::future::Future;
async fn f() {
let v = vec![1, 2, 3i32];
spawn(async { //~ ERROR E0373
println!("{:?}", v) // v might go out of scope before async block runs
});
}
fn spawn<F: Future + Send + 'static>(future: F) {
unimplemented!()
}Solution: Move the variable into the async block:
rust
spawn(async move {
println!("{:?}", v)
})E0373:异步块捕获短生命周期变量:
rust
use std::future::Future;
async fn f() {
let v = vec![1, 2, 3i32];
spawn(async { //~ 错误E0373
println!("{:?}", v) // v可能在异步块运行前就离开作用域
});
}
fn spawn<F: Future + Send + 'static>(future: F) {
unimplemented!()
}解决方案:将变量移动到异步块中:
rust
spawn(async move {
println!("{:?}", v)
})Unsafe Code and FFI
不安全代码与FFI
When to Use Unsafe
何时使用Unsafe
Rust's keyword allows operations that the compiler cannot verify:
unsafe- Dereferencing raw pointers
- Calling unsafe functions or methods
- Accessing or modifying mutable static variables
- Implementing unsafe traits
- Accessing fields of unions
Unsafe Dereference Example:
rust
macro_rules! unsafe_deref {
() => {
*(&() as *const ())
};
}Rust的关键字允许编译器无法验证的操作:
unsafe- 解引用原始指针
- 调用不安全函数或方法
- 访问或修改可变静态变量
- 实现不安全trait
- 访问联合体的字段
不安全解引用示例:
rust
macro_rules! unsafe_deref {
() => {
*(&() as *const ())
};
}Memory Safety with Unsafe
不安全代码的内存安全
Unsafe Sync Implementation:
rust
use std::cell::Cell;
struct NotThreadSafe<T> {
value: Cell<T>,
}
unsafe impl<T> Sync for NotThreadSafe<T> {}
static A: NotThreadSafe<usize> = NotThreadSafe { value : Cell::new(1) };
static B: &'static NotThreadSafe<usize> = &A; // ok!This is because you must manually ensure thread safety. is not by default, so this implementation requires careful reasoning.
unsafeCellSync不安全Sync实现:
rust
use std::cell::Cell;
struct NotThreadSafe<T> {
value: Cell<T>,
}
unsafe impl<T> Sync for NotThreadSafe<T> {}
static A: NotThreadSafe<usize> = NotThreadSafe { value : Cell::new(1) };
static B: &'static NotThreadSafe<usize> = &A; // 正常!这是的,因为你必须手动确保线程安全。默认不实现,因此该实现需要仔细的逻辑验证。
unsafeCellSyncFFI (Foreign Function Interface)
FFI(外部函数接口)
Calling C Functions from Rust:
rust
use std::mem;
#[link(name = "foo")]
extern "C" {
fn do_twice(f: unsafe extern "C" fn(i32) -> i32, arg: i32) -> i32;
}
unsafe extern "C" fn add_one(x: i32) -> i32 {
x + 1
}
unsafe extern "C" fn add_two(x: i64) -> i64 {
x + 2
}
fn main() {
let answer = unsafe { do_twice(add_one, 5) };
println!("The answer is: {}", answer);
// Type-mismatched call (unsafe):
println!("With CFI enabled, you should not see the next answer");
let f: unsafe extern "C" fn(i32) -> i32 = unsafe {
mem::transmute::<*const u8, unsafe extern "C" fn(i32) -> i32>(add_two as *const u8)
};
let next_answer = unsafe { do_twice(f, 5) };
println!("The next answer is: {}", next_answer);
}Control Flow Integrity (CFI):
With CFI enabled, the type-mismatched transmute causes program termination, preventing control flow hijacking.
Inline Assembly for System Calls:
rust
static UNMAP_BASE: usize;
const MEM_RELEASE: usize;
static VirtualFree: usize;
const OffPtr: usize;
const OffFn: usize;
core::arch::asm!("
push {free_type}
push {free_size}
push {base}
mov eax, fs:[30h]
mov eax, [eax+8h]
add eax, {off_fn}
mov [eax-{off_fn}+{off_ptr}], eax
push eax
jmp {virtual_free}
",
off_ptr = const OffPtr,
off_fn = const OffFn,
free_size = const 0,
free_type = const MEM_RELEASE,
virtual_free = sym VirtualFree,
base = sym UNMAP_BASE,
options(noreturn),
);This demonstrates direct system calls using inline assembly for Windows memory deallocation.
从Rust调用C函数:
rust
use std::mem;
#[link(name = "foo")]
extern "C" {
fn do_twice(f: unsafe extern "C" fn(i32) -> i32, arg: i32) -> i32;
}
unsafe extern "C" fn add_one(x: i32) -> i32 {
x + 1
}
unsafe extern "C" fn add_two(x: i64) -> i64 {
x + 2
}
fn main() {
let answer = unsafe { do_twice(add_one, 5) };
println!("The answer is: {}", answer);
// 类型不匹配的调用(不安全):
println!("With CFI enabled, you should not see the next answer");
let f: unsafe extern "C" fn(i32) -> i32 = unsafe {
mem::transmute::<*const u8, unsafe extern "C" fn(i32) -> i32>(add_two as *const u8)
};
let next_answer = unsafe { do_twice(f, 5) };
println!("The next answer is: {}", next_answer);
}控制流完整性(CFI):
启用CFI后,类型不匹配的transmute会导致程序终止,防止控制流劫持。
用于系统调用的内联汇编:
rust
static UNMAP_BASE: usize;
const MEM_RELEASE: usize;
static VirtualFree: usize;
const OffPtr: usize;
const OffFn: usize;
core::arch::asm!("
push {free_type}
push {free_size}
push {base}
mov eax, fs:[30h]
mov eax, [eax+8h]
add eax, {off_fn}
mov [eax-{off_fn}+{off_ptr}], eax
push eax
jmp {virtual_free}
",
off_ptr = const OffPtr,
off_fn = const OffFn,
free_size = const 0,
free_type = const MEM_RELEASE,
virtual_free = sym VirtualFree,
base = sym UNMAP_BASE,
options(noreturn),
);这展示了使用内联汇编直接调用Windows内存释放的系统调用。
Error Handling
错误处理
Result and Option Types
Result与Option类型
Rust uses and for error handling:
Result<T, E>Option<T>rust
fn divide(a: i32, b: i32) -> Result<i32, String> {
if b == 0 {
Err("Division by zero".to_string())
} else {
Ok(a / b)
}
}
fn main() {
match divide(10, 2) {
Ok(result) => println!("Result: {}", result),
Err(e) => println!("Error: {}", e),
}
}Rust使用和进行错误处理:
Result<T, E>Option<T>rust
fn divide(a: i32, b: i32) -> Result<i32, String> {
if b == 0 {
Err("Division by zero".to_string())
} else {
Ok(a / b)
}
}
fn main() {
match divide(10, 2) {
Ok(result) => println!("Result: {}", result),
Err(e) => println!("Error: {}", e),
}
}The ? Operator
?运算符
rust
fn process_file(path: &str) -> Result<String, std::io::Error> {
let content = std::fs::read_to_string(path)?;
Ok(content.to_uppercase())
}The operator propagates errors up the call stack, similar to exceptions but explicit in the type signature.
?rust
fn process_file(path: &str) -> Result<String, std::io::Error> {
let content = std::fs::read_to_string(path)?;
Ok(content.to_uppercase())
}?Custom Error Types
自定义错误类型
rust
use std::fmt;
#[derive(Debug)]
enum AppError {
IoError(std::io::Error),
ParseError(std::num::ParseIntError),
Custom(String),
}
impl fmt::Display for AppError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AppError::IoError(e) => write!(f, "IO error: {}", e),
AppError::ParseError(e) => write!(f, "Parse error: {}", e),
AppError::Custom(msg) => write!(f, "Error: {}", msg),
}
}
}
impl std::error::Error for AppError {}rust
use std::fmt;
#[derive(Debug)]
enum AppError {
IoError(std::io::Error),
ParseError(std::num::ParseIntError),
Custom(String),
}
impl fmt::Display for AppError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AppError::IoError(e) => write!(f, "IO error: {}", e),
AppError::ParseError(e) => write!(f, "Parse error: {}", e),
AppError::Custom(msg) => write!(f, "Error: {}", msg),
}
}
}
impl std::error::Error for AppError {}Memory Safety and Sanitizers
内存安全与Sanitizers
AddressSanitizer
AddressSanitizer
Detecting Stack Buffer Overflow:
rust
fn main() {
let xs = [0, 1, 2, 3];
let _y = unsafe { *xs.as_ptr().offset(4) };
}Build with AddressSanitizer:
shell
$ export RUSTFLAGS=-Zsanitizer=address RUSTDOCFLAGS=-Zsanitizer=address
$ cargo run -Zbuild-std --target x86_64-unknown-linux-gnuOutput:
==37882==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffe400e6250
READ of size 4 at 0x7ffe400e6250 thread T0
#0 0x5609a841fb1f in example::main::h628ffc6626ed85b2 /.../src/main.rs:3:23
Address 0x7ffe400e6250 is located in stack of thread T0 at offset 48 in frame
This frame has 1 object(s):
[32, 48) 'xs' (line 2) <== Memory access at offset 48 overflows this variableDetecting Heap Buffer Overflow:
rust
fn main() {
let xs = vec![0, 1, 2, 3];
let _y = unsafe { *xs.as_ptr().offset(4) };
}Detecting Use-After-Scope:
rust
static mut P: *mut usize = std::ptr::null_mut();
fn main() {
unsafe {
{
let mut x = 0;
P = &mut x;
}
std::ptr::write_volatile(P, 123); // P points to dropped variable
}
}AddressSanitizer output:
==39249==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7ffc7ed3e1a0
WRITE of size 8 at 0x7ffc7ed3e1a0 thread T0检测栈缓冲区溢出:
rust
fn main() {
let xs = [0, 1, 2, 3];
let _y = unsafe { *xs.as_ptr().offset(4) };
}使用AddressSanitizer构建:
shell
$ export RUSTFLAGS=-Zsanitizer=address RUSTDOCFLAGS=-Zsanitizer=address
$ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu输出:
==37882==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffe400e6250
READ of size 4 at 0x7ffe400e6250 thread T0
#0 0x5609a841fb1f in example::main::h628ffc6626ed85b2 /.../src/main.rs:3:23
Address 0x7ffe400e6250 is located in stack of thread T0 at offset 48 in frame
This frame has 1 object(s):
[32, 48) 'xs' (line 2) <== Memory access at offset 48 overflows this variable检测堆缓冲区溢出:
rust
fn main() {
let xs = vec![0, 1, 2, 3];
let _y = unsafe { *xs.as_ptr().offset(4) };
}检测作用域后使用:
rust
static mut P: *mut usize = std::ptr::null_mut();
fn main() {
unsafe {
{
let mut x = 0;
P = &mut x;
}
std::ptr::write_volatile(P, 123); // P指向已销毁的变量
}
}AddressSanitizer输出:
==39249==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7ffc7ed3e1a0
WRITE of size 8 at 0x7ffc7ed3e1a0 thread T0Performance Optimization
性能优化
Zero-Cost Abstractions
零成本抽象
Rust provides high-level abstractions without runtime overhead:
rust
// Iterator chains are optimized to simple loops
let sum: i32 = (1..100)
.filter(|x| x % 2 == 0)
.map(|x| x * x)
.sum();The compiler optimizes this to a tight loop equivalent to manual iteration.
Rust提供高级抽象且无运行时开销:
rust
// 迭代器链会被优化为简单循环
let sum: i32 = (1..100)
.filter(|x| x % 2 == 0)
.map(|x| x * x)
.sum();编译器会将其优化为与手动迭代等效的紧凑循环。
Inlining and Monomorphization
内联与单态化
Generic functions are monomorphized (specialized) for each concrete type:
rust
#[inline]
fn add<T: std::ops::Add<Output = T>>(a: T, b: T) -> T {
a + b
}
let x = add(5, 3); // Specialized for i32
let y = add(5.0, 3.0); // Specialized for f64泛型函数会针对每个具体类型进行单态化(特化):
rust
#[inline]
fn add<T: std::ops::Add<Output = T>>(a: T, b: T) -> T {
a + b
}
let x = add(5, 3); // 针对i32特化
let y = add(5.0, 3.0); // 针对f64特化Smart Pointer Overhead
智能指针开销
Different smart pointers have different costs:
- : Single heap allocation, no overhead
Box<T> - : Reference counting, small overhead per clone/drop
Rc<T> - : Atomic reference counting, higher overhead for thread safety
Arc<T> - : Lock acquisition overhead
Mutex<T> - : Runtime borrow checking overhead
RefCell<T>
不同智能指针的开销不同:
- :单次堆分配,无额外开销
Box<T> - :引用计数,每次克隆/销毁有少量开销
Rc<T> - :原子引用计数,线程安全带来更高开销
Arc<T> - :锁获取开销
Mutex<T> - :运行时借用检查开销
RefCell<T>
Avoiding Allocations
避免不必要的分配
rust
// Bad: Allocates a new String
fn greet_bad(name: &str) -> String {
format!("Hello, {}", name)
}
// Good: Returns a reference, no allocation
fn greet_good(name: &str) -> impl std::fmt::Display + '_ {
format_args!("Hello, {}", name)
}rust
// 不佳:分配新的String
fn greet_bad(name: &str) -> String {
format!("Hello, {}", name)
}
// 良好:返回引用,无分配
fn greet_good(name: &str) -> impl std::fmt::Display + '_ {
format_args!("Hello, {}", name)
}Common Patterns and Idioms
常见模式与惯用写法
Builder Pattern
构建器模式
rust
struct Config {
host: String,
port: u16,
timeout: u64,
}
impl Config {
fn builder() -> ConfigBuilder {
ConfigBuilder::default()
}
}
#[derive(Default)]
struct ConfigBuilder {
host: Option<String>,
port: Option<u16>,
timeout: Option<u64>,
}
impl ConfigBuilder {
fn host(mut self, host: impl Into<String>) -> Self {
self.host = Some(host.into());
self
}
fn port(mut self, port: u16) -> Self {
self.port = Some(port);
self
}
fn build(self) -> Config {
Config {
host: self.host.unwrap_or_else(|| "localhost".to_string()),
port: self.port.unwrap_or(8080),
timeout: self.timeout.unwrap_or(30),
}
}
}rust
struct Config {
host: String,
port: u16,
timeout: u64,
}
impl Config {
fn builder() -> ConfigBuilder {
ConfigBuilder::default()
}
}
#[derive(Default)]
struct ConfigBuilder {
host: Option<String>,
port: Option<u16>,
timeout: Option<u64>,
}
impl ConfigBuilder {
fn host(mut self, host: impl Into<String>) -> Self {
self.host = Some(host.into());
self
}
fn port(mut self, port: u16) -> Self {
self.port = Some(port);
self
}
fn build(self) -> Config {
Config {
host: self.host.unwrap_or_else(|| "localhost".to_string()),
port: self.port.unwrap_or(8080),
timeout: self.timeout.unwrap_or(30),
}
}
}Newtype Pattern
Newtype模式
rust
struct UserId(u64);
struct PostId(u64);
fn get_user(id: UserId) -> User { /* ... */ }
// This won't compile: type safety!
// get_user(PostId(42));rust
struct UserId(u64);
struct PostId(u64);
fn get_user(id: UserId) -> User { /* ... */ }
// 这无法编译:类型安全保障!
// get_user(PostId(42));RAII (Resource Acquisition Is Initialization)
RAII(资源获取即初始化)
rust
struct FileGuard {
file: std::fs::File,
}
impl FileGuard {
fn new(path: &str) -> std::io::Result<Self> {
Ok(FileGuard {
file: std::fs::File::create(path)?,
})
}
}
impl Drop for FileGuard {
fn drop(&mut self) {
println!("File closed automatically");
}
}rust
struct FileGuard {
file: std::fs::File,
}
impl FileGuard {
fn new(path: &str) -> std::io::Result<Self> {
Ok(FileGuard {
file: std::fs::File::create(path)?,
})
}
}
impl Drop for FileGuard {
fn drop(&mut self) {
println!("File closed automatically");
}
}Closure Patterns and Errors
闭包模式与错误
E0500: Closure Borrowing Conflict
E0500:闭包借用冲突
Problem:
rust
fn you_know_nothing(jon_snow: &mut i32) {
let nights_watch = &jon_snow;
let starks = || {
*jon_snow = 3; // error: closure requires unique access to `jon_snow`
// but it is already borrowed
};
println!("{}", nights_watch);
}Solution:
rust
fn you_know_nothing(jon_snow: &mut i32) {
let nights_watch = &jon_snow;
println!("{}", nights_watch); // Use the borrow first
// Borrow ends here (non-lexical lifetimes)
let starks = || {
*jon_snow = 3; // Now OK
};
}问题:
rust
fn you_know_nothing(jon_snow: &mut i32) {
let nights_watch = &jon_snow;
let starks = || {
*jon_snow = 3; // 错误:闭包需要对`jon_snow`的独占访问,但它已被借用
};
println!("{}", nights_watch);
}解决方案:
rust
fn you_know_nothing(jon_snow: &mut i32) {
let nights_watch = &jon_snow;
println!("{}", nights_watch); // 先使用借用
// 借用在此结束(非词法生命周期)
let starks = || {
*jon_snow = 3; // 现在可以正常使用
};
}E0502: Mutable and Immutable Borrows
E0502:可变与不可变借用共存
Problem:
rust
fn bar(x: &mut i32) {}
fn foo(a: &mut i32) {
let y = &a;
bar(a); // Error: cannot borrow as mutable while borrowed as immutable
println!("{}", y);
}Solution:
rust
fn bar(x: &mut i32) {}
fn foo(a: &mut i32) {
bar(a); // Mutable borrow first
let y = &a; // Immutable borrow after mutable borrow ends
println!("{}", y);
}问题:
rust
fn bar(x: &mut i32) {}
fn foo(a: &mut i32) {
let y = &a;
bar(a); // 错误:在不可变借用期间无法进行可变借用
println!("{}", y);
}解决方案:
rust
fn bar(x: &mut i32) {}
fn foo(a: &mut i32) {
bar(a); // 先进行可变借用
let y = &a; // 可变借用结束后再进行不可变借用
println!("{}", y);
}E0505: Move of Borrowed Value
E0505:移动已借用的值
Problem:
rust
struct Value {}
fn borrow(val: &Value) {}
fn eat(val: Value) {}
fn main() {
let x = Value{};
let _ref_to_val: &Value = &x;
eat(x); // Error: cannot move x while borrowed
borrow(_ref_to_val);
}问题:
rust
struct Value {}
fn borrow(val: &Value) {}
fn eat(val: Value) {}
fn main() {
let x = Value{};
let _ref_to_val: &Value = &x;
eat(x); // 错误:值已被借用,无法移动
borrow(_ref_to_val);
}E0524: Concurrent Mutable Borrows in Closures
E0524:闭包中的并发可变借用
Problem:
rust
fn set(x: &mut isize) {
*x += 4;
}
fn dragoooon(x: &mut isize) {
let mut c1 = || set(x);
let mut c2 = || set(x); // error: two closures trying to borrow mutably
c2();
c1();
}Solution 1: Sequential Execution (Non-Lexical Lifetimes)
rust
fn set(x: &mut isize) {
*x += 4;
}
fn dragoooon(x: &mut isize) {
{
let mut c1 = || set(&mut *x);
c1();
} // `c1` has been dropped here so we're free to use `x` again!
let mut c2 = || set(&mut *x);
c2();
}Solution 2: Rc + RefCell for Shared Mutable Access
rust
use std::rc::Rc;
use std::cell::RefCell;
fn set(x: &mut isize) {
*x += 4;
}
fn dragoooon(x: &mut isize) {
let x = Rc::new(RefCell::new(x));
let y = Rc::clone(&x);
let mut c1 = || { let mut x2 = x.borrow_mut(); set(&mut x2); };
let mut c2 = || { let mut x2 = y.borrow_mut(); set(&mut x2); };
c2();
c1();
}问题:
rust
fn set(x: &mut isize) {
*x += 4;
}
fn dragoooon(x: &mut isize) {
let mut c1 = || set(x);
let mut c2 = || set(x); // 错误:两个闭包尝试可变借用同一变量
c2();
c1();
}解决方案1:顺序执行(非词法生命周期)
rust
fn set(x: &mut isize) {
*x += 4;
}
fn dragoooon(x: &mut isize) {
{
let mut c1 = || set(&mut *x);
c1();
} // `c1`已被销毁,现在可以再次使用`x`!
let mut c2 = || set(&mut *x);
c2();
}解决方案2:使用Rc + RefCell实现共享可变访问
rust
use std::rc::Rc;
use std::cell::RefCell;
fn set(x: &mut isize) {
*x += 4;
}
fn dragoooon(x: &mut isize) {
let x = Rc::new(RefCell::new(x));
let y = Rc::clone(&x);
let mut c1 = || { let mut x2 = x.borrow_mut(); set(&mut x2); };
let mut c2 = || { let mut x2 = y.borrow_mut(); set(&mut x2); };
c2();
c1();
}E0507: Moving Borrowed Content
E0507:移动已借用的内容
Problem:
rust
use std::cell::RefCell;
struct TheDarkKnight;
impl TheDarkKnight {
fn nothing_is_true(self) {}
}
fn main() {
let x = RefCell::new(TheDarkKnight);
x.borrow().nothing_is_true(); // Error: cannot move out of borrowed content
}Solution 1: Take a Reference
rust
impl TheDarkKnight {
fn nothing_is_true(&self) {} // Change to &self
}
fn main() {
let x = RefCell::new(TheDarkKnight);
x.borrow().nothing_is_true(); // OK
}Solution 2: Reclaim Ownership
rust
fn main() {
let x = RefCell::new(TheDarkKnight);
let x = x.into_inner(); // Reclaim ownership
x.nothing_is_true(); // OK
}问题:
rust
use std::cell::RefCell;
struct TheDarkKnight;
impl TheDarkKnight {
fn nothing_is_true(self) {}
}
fn main() {
let x = RefCell::new(TheDarkKnight);
x.borrow().nothing_is_true(); // 错误:无法从借用的内容中移动
}解决方案1:使用引用
rust
impl TheDarkKnight {
fn nothing_is_true(&self) {} // 修改为&self
}
fn main() {
let x = RefCell::new(TheDarkKnight);
x.borrow().nothing_is_true(); // 正常
}解决方案2:重新获取所有权
rust
fn main() {
let x = RefCell::new(TheDarkKnight);
let x = x.into_inner(); // 重新获取所有权
x.nothing_is_true(); // 正常
}Production Patterns
生产环境模式
Structured Logging
结构化日志
rust
use tracing::{info, warn, error, instrument};
#[instrument]
async fn process_request(id: u64) -> Result<(), Error> {
info!(request_id = id, "Processing request");
match do_work(id).await {
Ok(_) => {
info!("Request completed successfully");
Ok(())
}
Err(e) => {
error!(error = ?e, "Request failed");
Err(e)
}
}
}rust
use tracing::{info, warn, error, instrument};
#[instrument]
async fn process_request(id: u64) -> Result<(), Error> {
info!(request_id = id, "Processing request");
match do_work(id).await {
Ok(_) => {
info!("Request completed successfully");
Ok(())
}
Err(e) => {
error!(error = ?e, "Request failed");
Err(e)
}
}
}Configuration Management
配置管理
rust
use serde::Deserialize;
#[derive(Deserialize)]
struct AppConfig {
database_url: String,
server_port: u16,
log_level: String,
}
fn load_config() -> Result<AppConfig, config::ConfigError> {
config::Config::builder()
.add_source(config::File::with_name("config"))
.add_source(config::Environment::with_prefix("APP"))
.build()?
.try_deserialize()
}rust
use serde::Deserialize;
#[derive(Deserialize)]
struct AppConfig {
database_url: String,
server_port: u16,
log_level: String,
}
fn load_config() -> Result<AppConfig, config::ConfigError> {
config::Config::builder()
.add_source(config::File::with_name("config"))
.add_source(config::Environment::with_prefix("APP"))
.build()?
.try_deserialize()
}Graceful Shutdown
优雅关闭
rust
use tokio::signal;
async fn shutdown_signal() {
let ctrl_c = async {
signal::ctrl_c()
.await
.expect("failed to install Ctrl+C handler");
};
#[cfg(unix)]
let terminate = async {
signal::unix::signal(signal::unix::SignalKind::terminate())
.expect("failed to install signal handler")
.recv()
.await;
};
#[cfg(not(unix))]
let terminate = std::future::pending::<()>();
tokio::select! {
_ = ctrl_c => {},
_ = terminate => {},
}
println!("Shutdown signal received, starting graceful shutdown");
}rust
use tokio::signal;
async fn shutdown_signal() {
let ctrl_c = async {
signal::ctrl_c()
.await
.expect("failed to install Ctrl+C handler");
};
#[cfg(unix)]
let terminate = async {
signal::unix::signal(signal::unix::SignalKind::terminate())
.expect("failed to install signal handler")
.recv()
.await;
};
#[cfg(not(unix))]
let terminate = std::future::pending::<()>();
tokio::select! {
_ = ctrl_c => {},
_ = terminate => {},
}
println!("Shutdown signal received, starting graceful shutdown");
}Connection Pooling
连接池
rust
use deadpool_postgres::{Config, Pool, Runtime};
use tokio_postgres::NoTls;
async fn create_pool() -> Pool {
let mut cfg = Config::new();
cfg.host = Some("localhost".to_string());
cfg.dbname = Some("mydb".to_string());
cfg.create_pool(Some(Runtime::Tokio1), NoTls)
.expect("Failed to create pool")
}
async fn query_user(pool: &Pool, id: i64) -> Result<User, Error> {
let client = pool.get().await?;
let row = client
.query_one("SELECT * FROM users WHERE id = $1", &[&id])
.await?;
Ok(User::from_row(row))
}rust
use deadpool_postgres::{Config, Pool, Runtime};
use tokio_postgres::NoTls;
async fn create_pool() -> Pool {
let mut cfg = Config::new();
cfg.host = Some("localhost".to_string());
cfg.dbname = Some("mydb".to_string());
cfg.create_pool(Some(Runtime::Tokio1), NoTls)
.expect("Failed to create pool")
}
async fn query_user(pool: &Pool, id: i64) -> Result<User, Error> {
let client = pool.get().await?;
let row = client
.query_one("SELECT * FROM users WHERE id = $1", &[&id])
.await?;
Ok(User::from_row(row))
}Best Practices
最佳实践
API Design
API设计
- Use References by Default: Accept instead of
&Tunless you need ownershipT - Return Owned Types: Return instead of
Stringfor simpler APIs&str - Implement Standard Traits: ,
Debug,Clone,PartialEq,SendSync - Use for Flexibility:
Into<T>fn set_name(&mut self, name: impl Into<String>) - Leverage the Type System: Use newtypes, enums, and Result for correctness
- 默认使用引用:接受而非
&T,除非你需要所有权T - 返回拥有型类型:返回而非
String以简化API&str - 实现标准trait:、
Debug、Clone、PartialEq、SendSync - 使用提升灵活性:
Into<T>fn set_name(&mut self, name: impl Into<String>) - 利用类型系统:使用newtype、枚举和Result保障正确性
Testing Patterns
测试模式
rust
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_addition() {
assert_eq!(add(2, 2), 4);
}
#[test]
#[should_panic(expected = "division by zero")]
fn test_divide_by_zero() {
divide(10, 0);
}
#[tokio::test]
async fn test_async_function() {
let result = fetch_data().await;
assert!(result.is_ok());
}
}rust
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_addition() {
assert_eq!(add(2, 2), 4);
}
#[test]
#[should_panic(expected = "division by zero")]
fn test_divide_by_zero() {
divide(10, 0);
}
#[tokio::test]
async fn test_async_function() {
let result = fetch_data().await;
assert!(result.is_ok());
}
}Documentation
文档
rust
/// Calculates the sum of two numbers.
///
/// # Examples
///
/// ```
/// let result = add(2, 2);
/// assert_eq!(result, 4);
/// ```
///
/// # Panics
///
/// This function will panic if the result overflows.
pub fn add(a: i32, b: i32) -> i32 {
a.checked_add(b).expect("overflow in add")
}rust
/// 计算两个数字的和。
///
/// # 示例
///
/// ```
/// let result = add(2, 2);
/// assert_eq!(result, 4);
/// ```
///
/// # 恐慌情况
///
/// 如果结果溢出,该函数会触发恐慌。
pub fn add(a: i32, b: i32) -> i32 {
a.checked_add(b).expect("overflow in add")
}Dependency Management
依赖管理
toml
[dependencies]
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
tracing = "0.1"
[dev-dependencies]
criterion = "0.5"
[profile.release]
lto = true
codegen-units = 1toml
[dependencies]
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
tracing = "0.1"
[dev-dependencies]
criterion = "0.5"
[profile.release]
lto = true
codegen-units = 1Troubleshooting
故障排查
Common Borrow Checker Issues
常见借用检查器问题
Issue: "Cannot borrow as mutable because it is also borrowed as immutable"
Solution: Ensure mutable and immutable borrows don't overlap in scope
Issue: "Cannot move out of borrowed content"
Solution: Clone the value, take a reference, or use
Rc<RefCell<T>>Issue: "Lifetime issues with references"
Solution: Add explicit lifetime annotations or restructure code to avoid complex lifetimes
问题:“无法可变借用,因为它同时被不可变借用”
解决方案:确保可变借用与不可变借用的作用域不重叠
问题:“无法从已借用的内容中移动”
解决方案:克隆值、使用引用,或使用
Rc<RefCell<T>>问题:“引用的生命周期问题”
解决方案:添加显式生命周期注解,或重构代码以避免复杂的生命周期
Performance Issues
性能问题
Issue: Slow compilation times
Solution: Use incremental compilation, reduce generic instantiations, use
cargo checkIssue: Runtime performance slower than expected
Solution: Profile with , enable LTO, check for unnecessary allocations/clones
perfIssue: High memory usage
Solution: Use references instead of clones, consider streaming data, profile with Valgrind
问题:编译速度慢
解决方案:使用增量编译、减少泛型实例化、使用
cargo check问题:运行时性能低于预期
解决方案:使用进行性能分析、启用LTO、检查不必要的分配/克隆
perf问题:内存占用高
解决方案:使用引用而非克隆、考虑流式处理数据、使用Valgrind进行分析
Concurrency Issues
并发问题
Issue: Deadlocks with multiple mutexes
Solution: Always acquire locks in the same order, use with timeout
try_lockIssue: Data races in unsafe code
Solution: Run with ThreadSanitizer, carefully review unsafe blocks
Issue: Async tasks not making progress
Solution: Check for blocking operations in async code, use for CPU-bound work
spawn_blocking问题:多个Mutex导致死锁
解决方案:始终按相同顺序获取锁、使用带超时的
try_lock问题:不安全代码中的数据竞争
解决方案:使用ThreadSanitizer运行、仔细审查不安全代码块
问题:异步任务无进展
解决方案:检查异步代码中的阻塞操作、对CPU密集型工作使用
spawn_blockingQuick Reference
快速参考
Smart Pointer Cheat Sheet
智能指针速查表
Box<T> - Heap allocation, single owner
Rc<T> - Reference counted, single-threaded
Arc<T> - Atomic reference counted, thread-safe
Mutex<T> - Mutual exclusion lock
RwLock<T> - Reader-writer lock
RefCell<T> - Runtime borrow checking
Cell<T> - Interior mutability for Copy typesBox<T> - 堆内存分配,单一所有者
Rc<T> - 引用计数,单线程
Arc<T> - 原子引用计数,线程安全
Mutex<T> - 互斥锁
RwLock<T> - 读写锁
RefCell<T> - 运行时借用检查
Cell<T> - Copy类型的内部可变性Common Trait Implementations
常见Trait实现
rust
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct MyStruct {
field: String,
}
impl Default for MyStruct {
fn default() -> Self {
Self {
field: String::new(),
}
}
}
impl std::fmt::Display for MyStruct {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "MyStruct({})", self.field)
}
}rust
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct MyStruct {
field: String,
}
impl Default for MyStruct {
fn default() -> Self {
Self {
field: String::new(),
}
}
}
impl std::fmt::Display for MyStruct {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "MyStruct({})", self.field)
}
}Async Runtime Comparison
异步运行时对比
Tokio: Full-featured, most popular, excellent ecosystem
async-std: Mirrors std library API, simpler for beginners
smol: Lightweight, minimal dependenciesTokio: 功能完整,最受欢迎,生态丰富
async-std: 镜像标准库API,对初学者更友好
smol: 轻量级,依赖极少Resources
资源
- The Rust Book: https://doc.rust-lang.org/book/
- Rust by Example: https://doc.rust-lang.org/rust-by-example/
- The Rustonomicon (unsafe Rust): https://doc.rust-lang.org/nomicon/
- Async Book: https://rust-lang.github.io/async-book/
- Rust Performance Book: https://nnethercote.github.io/perf-book/
- Crate Documentation: https://docs.rs/
Skill Version: 1.0.0
Last Updated: October 2025
Skill Category: Systems Programming, Performance, Memory Safety
Context7 Integration: Rust documentation and error code examples
- Rust官方书籍:https://doc.rust-lang.org/book/
- Rust示例教程:https://doc.rust-lang.org/rust-by-example/
- Rustonomicon(不安全Rust):https://doc.rust-lang.org/nomicon/
- 异步编程书籍:https://rust-lang.github.io/async-book/
- Rust性能优化书籍:https://nnethercote.github.io/perf-book/
- Crate文档:https://docs.rs/
技能版本:1.0.0
最后更新:2025年10月
技能分类:系统编程、性能优化、内存安全
Context7集成:Rust文档及错误代码示例