RUST Error Handling
Rust 程序设计语言 - Rust 程序设计语言 简体中文版 (kaisery.github.io)
错误处理
rust中的错误分为不可恢复错误和可恢复错误两类。对于我们想知会用户的错误或重试操作的错误,是可恢复的,例如文件不存在。而越界访问一个数组是一个严重bug,就可以按不可恢复错误处理。
Panic
rust中使用panic!
宏来处理不可恢复的错误,出现panic后,程序会打印错误信息,清理函数栈然后退出程序。默认情况下,程序panic退出前,反向遍历每一个函数栈,释放其中的数据,然后再退出,这个过程需要一定时间,所以可以再release版本的程序中配置为直接退出程序,让操作系统来释放程序运行过程中申请的资源。
在项目的 Cargo.toml文件中增加以下代码,在release版本可以减少程序退出占用的时间:
1 | [profile.release] |
可以直接调用panic!
宏退出程序
1 | panic!("I will be dead..."); |
在C语言中访问数组越界时,程序还是会按实际的地址访问内存空间中的数据,只是错误是未定义的,这样会导致偶发不可预期的故障。rust中只要访问越界,就会panic,并明确告诉错误的原因。
1 | let v = vec![1, 2, 3]; |
通过在执行程序时设置RUST_BACKTRACE=1
环境变量,就可以把出错时的调用栈打印出来。
1 | RUST_BACKTRACE=1 cargo run |
Result
enum Result有两种值,Ok用来表示成功返回值,Err表示失败时的返回值。
1 | enum Result<T, E> { |
例如以下代码打开一个文件,它的返回值为 Result<File, Error>
,然后可以使用match来处理两种情况,当Ok的时候,就把其中的file变量返回出去,如果失败了,就打印错误信息
1 | use std::fs::File; |
unwrap
Result<T, E>
的unwrap()方法简化错误处理,它内部实现了Ok时返回结果,错误时调用默认的panic。
1 | use std::fs::File; |
expect
Result<T, E>
的expect()方法它内部实现了Ok时返回结果,错误时可以指定的panic的信息
1 | use std::fs::File; |
传播错误
把函数执行过程中的错误返回给调用者,这样调用者可以看情况处理错误。可以使用match来直接返回错误
1 | use std::fs::File; |
为了简化match语句返回错误,rust支持使用?
操作符来提前返回错误。在一个函数调用结束时使用?,如果函数返回错误,就直接返回错误,不用写match。
1 | fn read_username_from_file() -> Result<String, io::Error> { |
?
会调用实现了From
Trait的结构体的from
方法,把调用函数返回的错误类型转换为当前?所在函数返回的错误类型。
使用 ?
后,可以方便的写链式调用。
1 | fn read_username_from_file() -> Result<String, io::Error> { |
?
操作符只能用于返回 Result
或 Option
(或其他类型实现了 FromResidual
)的函数,例如上面的函数返回值为Result.例如下面的会有编译错误,因为main的返回值类型为()
1 | fn main() { |
main可以返回任何实现了std::process::Termination
trait的类型
1 | use std::error::Error; |
Box<dyn Error>
表示任何类型的错误,所以这个main函数中可以用?
返回任何类型的错误.
?
返回Option类型时,如果时none会提前返回None,否则会返回Some中的值。
1 | fn last_char_of_first_line(text: &str) -> Option<char> { |
Summary
painic用在程序出现不可恢复的错误。当在开发例子程序,原型程序或测试程序时,使用unwrap或expect产生painic可以简化错误处理,提前发现错误,等后续正式的程序中进行错误处理让程序更健壮。
当程序执行的前提假设,约定或内存已经被破坏,或者使用了无效数据,这些错误程序已经无法控制,此时需要panic来提醒程序员强制处理这些问题。
result用在错误时符合预期的,但还是恢复的场景或程序还能处理,例如请求超时。
通过封装结构体,来确保数据的正确性,例如下面例子中获取一个1-100之间的数字,只要这个对象可以创建出来,它就一定满足1-100这个范围约定。
1 | pub struct Guess { |