错误处理与类型安全
学习 Rust 的错误处理机制,包括 Result、Option 类型和错误传播,对比 JavaScript 的异常处理
错误处理与类型安全
📖 学习目标
理解 Rust 的错误处理哲学,学会使用 Result
和 Option
类型,掌握错误传播模式,对比 JavaScript 的异常处理机制。
🎯 错误处理哲学对比
JavaScript 的异常处理
JavaScript 使用 try-catch 机制处理异常:
正在加载...
Rust 的错误处理
Rust 使用类型系统处理错误,没有异常机制:
正在加载...
错误处理差异
- 异常 vs 类型: JavaScript 使用异常,Rust 使用类型系统
- 运行时 vs 编译时: JavaScript 运行时检查,Rust 编译时检查
- 可恢复 vs 不可恢复: Rust 区分可恢复错误(Result)和不可恢复错误(panic)
- 显式 vs 隐式: Rust 强制显式处理错误,JavaScript 可以忽略异常
📦 Option 类型
处理可能为空的值
正在加载...
🔄 Result 类型
处理可能失败的操作
正在加载...
🎯 错误处理最佳实践
错误处理模式对比
正在加载...
高级错误处理库
在实际项目中,为了更方便地定义和处理错误,Rust 社区提供了许多优秀的错误处理库,例如:
thiserror
: 用于简化自定义错误类型的定义,特别是当错误需要包含额外信息或从其他错误类型派生时。它通过宏自动实现Display
和Error
trait。anyhow
: 用于简化错误传播,特别是在应用层代码中。它提供了一个简单的Result
类型别名anyhow::Result<T>
,并允许你轻松地将各种错误类型转换为anyhow::Error
。
这些库可以大大减少错误处理的样板代码,提高代码的可读性和可维护性。
🎯 练习题
练习 1: 实现 Option 方法
实现一个函数,从字符串中提取数字,返回 Option<i32>
:
查看答案
fn extract_number(s: &str) -> Option<i32> {s.chars().filter(|c| c.is_digit(10)).collect::<String>().parse::<i32>().ok()}fn main() {println!("{:?}", extract_number("abc123def")); // Some(123)println!("{:?}", extract_number("no numbers")); // Noneprintln!("{:?}", extract_number("456")); // Some(456)}
练习 2: 自定义错误类型
创建一个自定义错误类型,用于处理文件操作:
查看答案
use std::error::Error;use std::fmt;#[derive(Debug)]enum FileError {NotFound(String),PermissionDenied(String),InvalidFormat(String),}impl fmt::Display for FileError {fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {match self {FileError::NotFound(path) => write!(f, "文件未找到: {}", path),FileError::PermissionDenied(path) => write!(f, "权限被拒绝: {}", path),FileError::InvalidFormat(msg) => write!(f, "格式无效: {}", msg),}}}impl Error for FileError {}fn read_file(path: &str) -> Result<String, FileError> {if path.is_empty() {return Err(FileError::NotFound("路径为空".to_string()));}if path.contains("private") {return Err(FileError::PermissionDenied(path.to_string()));}if path.contains("invalid") {return Err(FileError::InvalidFormat("文件格式无效".to_string()));}Ok(format!("文件内容: {}", path))}fn main() {match read_file("test.txt") {Ok(content) => println!("成功: {}", content),Err(error) => println!("错误: {}", error),}match read_file("") {Ok(content) => println!("成功: {}", content),Err(error) => println!("错误: {}", error),}}
练习 3: 错误传播
创建一个函数链,每个函数都可能失败,使用 ?
操作符传播错误:
查看答案
fn validate_input(input: &str) -> Result<String, String> {if input.is_empty() {return Err("输入不能为空".to_string());}Ok(input.to_string())}fn process_data(data: &str) -> Result<String, String> {if data.len() < 3 {return Err("数据太短".to_string());}Ok(data.to_uppercase())}fn save_data(data: &str) -> Result<(), String> {if data.contains("error") {return Err("保存失败".to_string());}println!("保存数据: {}", data);Ok(())}fn process_pipeline(input: &str) -> Result<(), String> {let validated = validate_input(input)?;let processed = process_data(&validated)?;save_data(&processed)?;Ok(())}fn main() {match process_pipeline("hello") {Ok(_) => println!("处理成功"),Err(error) => println!("处理失败: {}", error),}match process_pipeline("") {Ok(_) => println!("处理成功"),Err(error) => println!("处理失败: {}", error),}}
📝 总结
在这一章中,我们学习了 Rust 的错误处理机制:
- Option 类型: 处理可能为空的值
- Result 类型: 处理可能失败的操作
- 错误传播: 使用
?
操作符传播错误 - 自定义错误: 创建自己的错误类型
- 与 JavaScript 对比: 类型安全 vs 异常处理
关键要点
- Rust 使用类型系统而不是异常处理错误
Option
和Result
强制显式处理错误情况?
操作符简化错误传播- 自定义错误类型提供更好的错误信息
下一步学习
在下一章中,我们将学习 Rust 的 Web 开发,了解如何使用 Rust 构建 Web 应用程序。
继续学习: Web 开发实战