Rust 错误处理:try/catch 及其他——完整指南

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

Rust 错误处理:摒弃 try/catch,拥抱安全性



与 Python 或 Java 不同,Rust 没有经典的 try/catch 结构。语言开发者选择了另一条道路,将错误处理作为类型系统的一部分。这并非一时兴起,而是一项基础性决策,它能够在编译阶段保证内存安全和程序行为的可预测性。在本文中,我们将深入探讨 Rust 中所有的错误处理方法:从基础的 Result 和 Option,到使用 ? 运算符和自定义错误类型的高级技巧。



1. 两大核心类型:Result 和 Option



在 Rust 中,所有错误分为两类:可恢复的(通过 Result 处理)和 不可恢复的(导致 panic!)。此外,还有 Option 类型,用于处理值可能不存在的情况。



Result 类型



Result<T, E> 是一个枚举(enum),它可以是 Ok(T)(成功并包含数据),也可以是 Err(E)(失败并包含错误描述)。这是处理预期错误(如 I/O 错误、解析错误、网络请求错误)的主要工具。



use std::fs::File;use std::io::Read;

fn read_file_content(path: &str) -> Result<String, std::io::Error> { let mut file = File::open(path)?; let mut content = String::new(); file.read_to_string(&mut content)?; Ok(content)}


Option 类型



Option<T> 是另一个枚举,它接受 Some(T)(有值)或 None(无值)。当数据缺失是正常情况而非错误时使用。



fn find_user(id: u32) -> Option<String> {    let users = vec!["Alice".to_string(), "Bob".to_string()];    users.get(id as usize).cloned()}

fn main() { match find_user(0) { Some(name) => println!("找到用户: {}", name), None => println!("未找到用户"), }}


2. ? 运算符——try/catch 的优雅替代



如果 Rust 有 try/catch,它会显得很笨重。相反,该语言提供了 ? 运算符。它的工作方式如下:如果结果是 Ok,则提取值并继续传递;如果是 Err,则立即从函数返回该错误。



use std::num::ParseIntError;

fn parse_and_double(input: &str) -> Result<i32, ParseIntError> { let value: i32 = input.parse()?; // 如果出错——立即 return Err Ok(value * 2)}

fn main() { match parse_and_double("42") { Ok(result) => println!("结果: {}", result), Err(e) => println!("解析错误: {}", e), }}


? 运算符只能用于返回 Result 或 Option 的函数中。这迫使开发者明确声明函数可能以错误结束——这与 Python 中的异常不同,后者可能从任何地方“抛出”。



3. 何时使用 panic! 和 unwrap



并非所有错误都需要处理。panic! 是一个用于不可恢复错误的宏。它会停止程序并展开堆栈(stack unwind)。仅在极端情况下使用它:



  • 紧急状态:违反无法修复的不变量。
  • 示例和原型:在教学代码或一次性脚本中。
  • 测试:用于验证代码在预期位置崩溃。


fn divide(a: i32, b: i32) -> i32 {    if b == 0 {        panic!("除以零!a={}, b={}", a, b);    }    a / b}


unwrap() 和 expect() 是 Result 和 Option 的便捷方法。如果值是 Ok 或 Some,它们会返回内部值;如果是 Err 或 None,则会触发 panic!。

博客

书籍推荐