Rust 错误处理与异步
更新时间:2026-08-29。本文回答:Rust 不用异常怎么处理错误?
async/await背后是什么?tokio 和 epoll 低延迟有何关系?
一、错误即值:Result 与 Option
Rust 没有异常机制(异常会悄悄跳过清理逻辑)。可恢复错误用 Result<T, E>,"可能为空"用 Option<T>:
rust
fn read_port(path: &str) -> Result<String, std::io::Error> {
std::fs::read_to_string(path) // 返回 Result
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let cfg = read_port("/etc/svc.conf")?; // ? 把错误向上传播
println!("{}", cfg.len());
Ok(())
}?是错误传播符:遇到Err立即返回,遇到Ok取出值继续。panic!留给"真不可能发生"的 bug(数组越界、unwrap 空值),等价于其他语言的致命异常——生产代码应尽量避免。
| 机制 | 用途 | 类比 |
|---|---|---|
Option<T> | 可能无值 | C++ std::optional、Go 的 (v, ok) |
Result<T, E> | 可能失败 | Go 多返回值、std::expected |
? | 错误上抛 | Go if err != nil { return err } 的紧凑版 |
panic! | 致命 bug | 不可恢复异常 |
和性能的关系:显式 Result 让错误路径在源码里可见可测,不会因为异常栈展开(C++ 栈展开)拖慢热路径。
二、async/await:无栈协程
async fn 返回一个 Future——一个惰性、可暂停/恢复的计算。它不自己跑,需要被运行时(如 tokio)await 驱动:
rust
use tokio::net::TcpListener;
async fn handle(mut s: tokio::net::TcpStream) {
// 异步读写,遇到 IO 等待时让出,不阻塞线程
}
#[tokio::main]
async fn main() -> std::io::Result<()> {
let listener = TcpListener::bind("127.0.0.1:8080").await?;
loop {
let (socket, _) = listener.accept().await?;
tokio::spawn(handle(socket)); // 每个连接一个轻量任务
}
}- 无栈协程:任务状态存在堆上的
Future里,而不是每个协程独占大栈,因此可轻松起几十万个任务。 - 多路复用:
tokio底层用epoll(Linux)在少量 worker 线程上驱动海量连接,和本站 epoll 网络低延迟 讲的是同一件事。
三、与 Go / C++ 的对比
| 维度 | Rust async | Go goroutine | C++ 异步 |
|---|---|---|---|
| 协程类型 | 无栈 Future | 有栈 goroutine | std::async/协程(C++20) |
| 调度 | tokio(用户态) | runtime(用户态) | 标准库/第三方 |
| 多路复用 | epoll/kqueue | netpoller(epoll) | io_uring/第三方 |
| 错误 | Result 显式 | error 值 | 异常/返回值 |
| 零成本 | 编译期内联 | 运行时调度器 | 视实现 |
四、与本站主线的衔接
| Rust 概念 | 本站对应 | 衔接文档 |
|---|---|---|
| tokio epoll 多路复用 | epoll 低延迟 | 无栈协程 + 事件驱动 |
Send/Sync 任务安全 | L4 内存序 | 跨线程传递的编译期把关 |
| 栈展开 vs panic | C++ 异常安全 | 错误路径可预测 |
| 性能剖析 | perf 火焰图 | cargo build 产物一样能 perf |
五、常见坑
await必须放在 async 上下文:在普通fn里直接调async fn不会执行,只构造了Future。- 阻塞操作毁掉异步:在
tokio任务里调用同步阻塞 IO(如普通std::fs),会卡住整个 worker 线程,要用tokio::fs等异步版本。 Send错误:把Rc(非Send)跨await点捕获进任务会编译失败——换Arc即可。
一句话总结
Rust 用 Result 把错误变成显式值(热路径可预测),用无栈 Future + tokio 做 epoll 多路复用的高吞吐异步——编译期管安全,运行时管吞吐,和本站低延迟主线一脉相承。
回到总纲:Rust 快速上手。