panic
panic!可以使用类似print!的参数打印信息。
panic发生的时候rust会清理线程的数据,比如申请的内存,打开的文件,按调用栈一层层清理,并最终结束线程,如果panic的是主线程则程序就会退出。
std::panic::catch_unwind()会拦截unwind。但不是所有的panic都有相同的unwind机制,所以可能不能catch住。
加入一个unwind在调用drop的时候触发了另一个panic则unwind就会终止。
panic的参数:
- -C panic=abort:立刻重视进程,不会unwinding,所以会减小程序的大小。
Result
Result
有一些有用的方法,其中as_ref
和as_mut
可以将转移值变成取引用,方便保留原值不被销毁。
println!
中{}
打印简单的信息,{:?}
打印详细的错误类型信息。error
的to_string
就是{}
中简单的信息, to_source
方法返回错误的上一次错误,返回类型是Option
。writeln!(stderr(), "error: {}", err)
可以将错误打印到标准错误,因为writeln!可以指定输出流。eprintln!
也可以,但如果出错会panic。
一些包经常定义一个Result
的别名,用来省略包里用到的相同的错误类型:pub type Result<T> = result::Result<T, Error>;
一个函数里的多个Result的错误类型如果不一样需要让函数的错误能够通过From trait将各种错误转换类型。如果想要过滤出某个错误类型可以用error.downcast_ref::<ErrorType>()
如果调用了一个方法返回了Result,程序不处理的化,编译器会给警告,用let _ = ...
可以消除警告。
在main函数返回Result,其Err类型需要支持{:?},这样在程序panic的时候会打印出相应的错误信息。
自定义Err类型,最简单的定义
#[derive(Debug, Clone)]
pub struct JsonError {
pub message: String,
pub line: usize,
pub column: usize,
}
如果要像标准库的err那样还要实现两个trait
use std::fmt;
// Errors should be printable.
impl fmt::Display for JsonError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{} ({}:{})", self.message, self.line, self.column)
}
}
// Errors should implement the std::error::Error trait,
// but the default definitions for the Error methods are fine.
impl std::error::Error for JsonError { }
也可以用第三方的crate,比如thiserror.
为什么要用Result:
- 可以强制程序员必须对可能出现的错误进行处理。
- 也方便将错误向上传递(使用
?
,既方便也不会隐藏处理) - 函数的返回类型是Result也能表民其有可能出错。
- 编译器会检查Result是否被处理,所以程序员不会忽略。
- 因为Result是一个类型,所以可以把成功返回和错误返回放到一个集合里,方便统计。
常用的方法map,map_err