常见的 error handing
程序中会出现的两种错误:错误、异常
异常
- 异常是开发者无法预料且超出自己能力范围的错误,例如:空指针
-
错误
典型的比如:建立TCP连接失败
- 开发者可以预料这种问题并且有能力去解决
-
Java:try-catch
代表:Java, Python, JS…
问题:
遇到不可恢复错误,程序奔溃退出(early crash)
-
Rust:两种实现可恢复/不可恢复错误语法
Result<T, E>
是一个泛型枚举panic!
是一个宏
不可恢复错误
最简单的创建方法:使用宏
fn main() {
panic!("this is a error"); // 使用宏创建一个不可恢复错误
println!("unreachable statement!");
}
同时还有一些常见宏可导致不可恢复错误
断言
fn main() {
assert!(1 == 2);
assert_eq!(1, 2); // 等效
}
未实现的代码
fn add(a: u32, b: u32) -> u32 {
unimplemented!()
}
fn main() {
println!("{}", add(1, 2));
}
不应该被访问的代码
fn divide_by_three(x: u32) -> u32 {
for i in 0.. {
if 3 * i < i {
// 溢出了
panic!("u32 overflow");
}
if x < 3 * i {
return i - 1;
}
}
// 这里其实是一定无法走到的,但是这里不写就会报错
// expected `u32` because of return type
// 按照其他语言的做法,可以return 0; 但是Rust可以用unreachable宏
unreachable!();
}
可恢复的错误
- Result
源码 ```rust
pub enum Result
#[lang = "Ok"]
#[stable(feature = "rust1", since = "1.0.0")]
Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
/// Contains the error value
#[lang = "Err"]
#[stable(feature = "rust1", since = "1.0.0")]
Err(#[stable(feature = "rust1", since = "1.0.0")] E),
}
- Ok/Err
```rust
fn main() {
let a: Result<u32, &'static str> = Result::Ok(1);
println!("{:?}", a); // Ok(1)
let b: Result<u32, &'static str> = Result::Err("result error");
println!("{:?}", b); // Err("result error")
}
- 标准库的一些方法返回的是一个Result
fn main() {
let result = std::fs::read("tmp/test.text");
match result {
Ok(data) => println!("{:?}", std::str::from_utf8(&data).unwrap()), // 不想处理from_utf8的Result error,就使用unwrap
Err(err) => println!("{:?}", err), // Os { code: 2, kind: NotFound, message: "No such file or directory" }
}
}
自定义错误与问号表达式
问号表达式
- 许多时候(尤其编写库的时候),不仅仅希望获取错误,更希望错误可以在上下文进行传递
问号表达式可以简便地传递错误
- 当函数的错误与当前错误的类型相同时,使用?可以直接将错误传递到函数外并终止函数执行
fn foo() -> Result<T, E> {
let x = bar()?; // bar的错误类型需要和foo相同(E)
...
}
- 当函数的错误与当前错误的类型相同时,使用?可以直接将错误传递到函数外并终止函数执行
?
的作用是将 Result 枚举的正常值取出,如果有错误就将错误返回出去 ```rust fn bar() -> Result<u32, &’static str> { Ok(0) }
fn foo() -> Result<i32, &’static str> { let a = bar()?; Ok(a as i32) }
fn main() { println!(“{:?}”, foo()); // Ok(0) }
```rust
fn bar() -> Result<u32, &'static str> {
Ok(0)
}
fn foo() -> Result<i32, &'static str> {
// 不用?表达式,就得用 match bar() 处理 Ok/Err
let a = bar()?;
Ok(a as i32)
}
fn main() {
println!("{:?}", foo()); // Ok(0)
}
创建自定义错误
包装自己的错误类型
#[derive(Debug)]
pub enum Error {
IO(std::io::ErrorKind),
}
impl From<std::io::Error> for Error {
fn from(error: std::io::Error) -> Self {
Error::IO(error.kind())
}
}
fn do_read_file() -> Result<(), Error> {
let data = std::fs::read("/temp/foo.txt")?;
let data_str = std::str::from_utf8(&data).unwrap();
println!("{:?}", data_str);
Ok(())
}
fn main() -> Result<(), Error> {
do_read_file()?;
Ok(())
} // Error: IO(NotFound)