
Rust 系统编程模式:零成本抽象与 FFI
Rust 承诺的“零成本抽象”意味着你无需为高级构造付出运行时开销。本指南探讨如何利用 trait 对象与泛型、编写安全的 unsafe 代码、通过 FFI 与 C 集成、开发嵌入式 Rust,以及衡量抽象在何处真正实现零成本。
实践中的零成本抽象
核心原则:你不使用的东西,就不需要付费。抽象在编译时被消除:
// 高级迭代器链
fn sum_of_squares(v: &[i32]) -> i32 {
v.iter()
.filter(|&&x| x % 2 == 0)
.map(|&x| x * x)
.sum()
}
// 编译为与以下代码基本相同的汇编:
fn sum_of_squares_manual(v: &[i32]) -> i32 {
let mut total = 0;
for &x in v {
if x % 2 == 0 {
total += x * x;
}
}
total
}
使用 Compiler Explorer (godbolt.org) 验证——两者生成相同的优化代码。

Trait 对象 vs. 泛型
在动态分发(trait 对象)和静态分发(泛型)之间选择具有实际的性能影响:
use std::fmt;
trait Drawable {
fn draw(&self);
fn bounding_box(&self) -> (f64, f64, f64, f64);
}
struct Circle { x: f64, y: f64, radius: f64 }
struct Rectangle { x: f64, y: f64, width: f64, height: f64 }
impl Drawable for Circle {
fn draw(&self) { println!("Drawing circle at ({}, {})", self.x, self.y); }
fn bounding_box(&self) -> (f64, f64, f64, f64) {
(self.x - self.radius, self.y - self.radius,
self.x + self.radius, self.y + self.radius)
}
}
impl Drawable for Rectangle {
fn draw(&self) { println!("Drawing rect at ({}, {})", self.x, self.y); }
fn bounding_box(&self) -> (f64, f64, f64, f64) {
(self.x, self.y, self.x + self.width, self.y + self.height)
}
}
// 静态分发:编译器为每种类型生成单独的代码
// 快速,无 vtable 查找,支持内联
fn draw_static<T: Drawable>(shape: &T) {
shape.draw();
}
// 动态分发:单一代码路径,运行时 vtable 查找
// 较慢,阻止内联,但允许异构集合
fn draw_dynamic(shape: &dyn Drawable) {
shape.draw();
}
fn main() {
let circle = Circle { x: 0.0, y: 0.0, radius: 5.0 };
let rect = Rectangle { x: 1.0, y: 1.0, width: 10.0, height: 5.0 };
// 静态:编译时单态化
draw_static(&circle);
draw_static(&rect);
// 动态:通过 vtable 运行时分发
let shapes: Vec<Box<dyn Drawable>> = vec![
Box::new(Circle { x: 0.0, y: 0.0, radius: 3.0 }),
Box::new(Rectangle { x: 0.0, y: 0.0, width: 5.0, height: 3.0 }),
];
for shape in &shapes {
draw_dynamic(shape.as_ref());
}
}
经验法则:在性能关键的代码中使用泛型。在需要异构集合或希望减少编译时间时使用 trait 对象。
Unsafe 代码:何时及如何使用
Unsafe Rust 对于 FFI、底层内存操作和某些性能关键模式是必要的:
// 原始指针操作
fn split_at_mut_safe<T>(slice: &mut [T], mid: usize) -> (&mut [T], &mut [T]) {
let len = slice.len();
assert!(mid <= len);
let ptr = slice.as_mut_ptr();
// 安全调用:ptr 有效,范围不重叠
unsafe {
(
std::slice::from_raw_parts_mut(ptr, mid),
std::slice::from_raw_parts_mut(ptr.add(mid), len - mid),
)
}
}
// 无锁编程的原子操作
use std::sync::atomic::{AtomicUsize, Ordering};
static COUNTER: AtomicUsize = AtomicUsize::new(0);
fn increment() -> usize {
COUNTER.fetch_add(1, Ordering::SeqCst)
}
// 将 unsafe 包装在安全 API 中(正确模式)
pub struct SafeBuffer {
ptr: *mut u8,
len: usize,
cap: usize,
}
impl SafeBuffer {
pub fn new(capacity: usize) -> Self {
let layout = std::alloc::Layout::array::<u8>(capacity).unwrap();
let ptr = unsafe { std::alloc::alloc(layout) };
SafeBuffer { ptr, len: 0, cap: capacity }
}
pub fn push(&mut self, byte: u8) {
assert!(self.len < self.cap, "Buffer overflow");
unsafe {
*self.ptr.add(self.len) = byte;
}
self.len += 1;
}
pub fn as_slice(&self) -> &[u8] {
unsafe { std::slice::from_raw_parts(self.ptr, self.len) }
}
}
impl Drop for SafeBuffer {
fn drop(&mut self) {
let layout = std::alloc::Layout::array::<u8>(self.cap).unwrap();
unsafe { std::alloc::dealloc(self.ptr, layout); }
}
}

FFI:从 Rust 调用 C
Rust 的 extern "C" 块实现了与 C 的无缝互操作:
// 声明 C 函数
extern "C" {
fn strlen(s: *const std::os::raw::c_char) -> usize;
fn malloc(size: usize) -> *mut std::os::raw::c_void;
fn free(ptr: *mut std::os::raw::c_void);
fn printf(format: *const std::os::raw::c_char, ...) -> std::os::raw::c_int;
}
// 安全包装器
fn c_strlen(s: &str) -> usize {
let c_str = std::ffi::CString::new(s).unwrap();
unsafe { strlen(c_str.as_ptr()) }
}
// 向 C 暴露 Rust 函数
#[no_mangle]
pub extern "C" fn rust_add(a: i32, b: i32) -> i32 {
a + b
}
#[no_mangle]
pub extern "C" fn rust_process_bytes(ptr: *const u8, len: usize) -> i32 {
if ptr.is_null() {
return -1;
}
let slice = unsafe { std::slice::from_raw_parts(ptr, len) };
slice.iter().sum::<u8>() as i32
}
使用 bindgen 工具自动生成 FFI 绑定:
// build.rs
fn main() {
println!("cargo:rerun-if-changed=wrapper.h");
let bindings = bindgen::Builder::default()
.header("wrapper.h")
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
.generate()
.expect("Unable to generate bindings");
bindings.write_to_file("src/bindings.rs").unwrap();
}
嵌入式 Rust
Rust 的 no_std 模式支持裸机编程:
#![no_std]
#![no_main]
use panic_halt as _;
use cortex_m_rt::entry;
use stm32f4xx_hal::{pac, prelude::*};
#[entry]
fn main() -> ! {
let dp = pac::Peripherals::take().unwrap();
let rcc = dp.RCC.constrain();
let clocks = rcc.cfgr.sysclk(84.MHz()).freeze();
let gpioa = dp.GPIOA.split();
let mut led = gpioa.pa5.into_push_pull_output();
loop {
led.set_high();
cortex_m::asm::delay(8_000_000);
led.set_low();
cortex_m::asm::delay(8_000_000);
}
}
性能测量
使用 criterion 进行统计严谨的基准测试:
[dev-dependencies]
criterion = { version = "0.5", features = ["html_reports"] }
[[bench]]
name = "my_bench"
harness = false
use criterion::{black_box, criterion_group, criterion_main, Criterion, BenchmarkId};
fn fibonacci(n: u64) -> u64 {
match n {
0 => 0,
1 => 1,
_ => fibonacci(n - 1) + fibonacci(n - 2),
}
}
fn fibonacci_iterative(n: u64) -> u64 {
let (mut a, mut b) = (0u64, 1u64);
for _ in 0..n {
let tmp = a + b;
a = b;
b = tmp;
}
a
}
fn bench_fibonacci(c: &mut Criterion) {
let mut group = c.benchmark_group("fibonacci");
for i in [10u64, 20, 30].iter() {
group.bench_with_input(
BenchmarkId::new("recursive", i),
i,
|b, i| b.iter(|| fibonacci(black_box(*i))),
);
group.bench_with_input(
BenchmarkId::new("iterative", i),
i,
|b, i| b.iter(|| fibonacci_iterative(black_box(*i))),
);
}
group.finish();
}
criterion_group!(benches, bench_fibonacci);
criterion_main!(benches);
使用 const 进行编译时计算
Rust 的 const 求值将工作移至编译时:
const fn factorial(n: u64) -> u64 {
if n == 0 { 1 } else { n * factorial(n - 1) }
}
const FACTORIAL_10: u64 = factorial(10); // 编译时计算
// 用于类型级整数的 Const 泛型
struct Matrix<const ROWS: usize, const COLS: usize> {
data: [[f64; COLS]; ROWS],
}
impl<const N: usize> Matrix<N, N> {
fn identity() -> Self {
let mut data = [[0.0; N]; N];
for i in 0..N {
data[i][i] = 1.0;
}
Matrix { data }
}
}
fn main() {
println!("10! = {}", FACTORIAL_10); // 3628800
let identity: Matrix<3, 3> = Matrix::identity();
}
结论
Rust 的零成本抽象模型让你能够编写表达力强、高级的代码,这些代码编译为紧凑的机器码。在性能关键路径上选择泛型而非 trait 对象,将 unsafe 代码封装在安全抽象中,并使用 FFI 来利用庞大的 C 生态系统。安全保证与原始性能的结合使 Rust 在 2026 年成为系统编程的独特选择。