常见的 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```rustfn 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,就使用unwrapErr(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) }
```rustfn bar() -> Result<u32, &'static str> {Ok(0)}fn foo() -> Result<i32, &'static str> {// 不用?表达式,就得用 match bar() 处理 Ok/Errlet 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)
