1. 自定义能引发 panic 的情况并在调用方处理的步骤
- 定义自定义错误类型:使用
enum
定义一个自定义错误类型,通常配合 std::fmt::Display
和 std::error::Error
特质来使其更易用。
- 编写能引发 panic 的函数:在函数中,当满足特定条件时,使用
panic!
宏并传入自定义错误类型的实例。
- 在调用方处理 panic:使用
catch_unwind
来捕获 panic,并对捕获到的结果进行处理。
2. 完整代码示例
use std::fmt;
use std::panic;
// 定义自定义错误类型
#[derive(Debug)]
struct MyCustomError {
message: String,
}
impl fmt::Display for MyCustomError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.message)
}
}
impl std::error::Error for MyCustomError {}
// 能引发 panic 的函数
fn might_panic() {
let should_panic = true;
if should_panic {
panic!(MyCustomError {
message: "This is a custom panic".to_string()
});
}
}
fn main() {
let result = panic::catch_unwind(|| {
might_panic();
});
match result {
Ok(_) => println!("Function executed successfully"),
Err(e) => {
if let Some(custom_error) = e.downcast_ref::<MyCustomError>() {
println!("Caught custom panic: {}", custom_error);
} else {
println!("Caught other panic: {:?}", e);
}
}
}
}
3. 库代码和应用代码中处理方式的差异
- 库代码:
- 通常库代码不应该直接
panic!
,因为库的使用者可能不期望库代码内部引发 panic 导致整个应用崩溃。库代码应倾向于返回 Result
类型,让调用者决定如何处理错误。
- 如果确实需要定义可能导致 panic 的情况,应该提供清晰的文档说明在什么情况下会发生,以及调用者应如何处理。
- 应用代码:
- 应用代码在调用库函数时,如果知道某个库函数可能引发 panic,可以使用
catch_unwind
来捕获并处理。
- 应用代码自身在一些特定情况下(例如初始化失败导致程序无法继续运行)也可以直接使用
panic!
,但要确保错误信息清晰,便于调试。