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_refas_mut可以将转移值变成取引用,方便保留原值不被销毁。

println!{}打印简单的信息,{:?}打印详细的错误类型信息。
errorto_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类型,最简单的定义

  1. #[derive(Debug, Clone)]
  2. pub struct JsonError {
  3. pub message: String,
  4. pub line: usize,
  5. pub column: usize,
  6. }

如果要像标准库的err那样还要实现两个trait

  1. use std::fmt;
  2. // Errors should be printable.
  3. impl fmt::Display for JsonError {
  4. fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
  5. write!(f, "{} ({}:{})", self.message, self.line, self.column)
  6. }
  7. }
  8. // Errors should implement the std::error::Error trait,
  9. // but the default definitions for the Error methods are fine.
  10. impl std::error::Error for JsonError { }

也可以用第三方的crate,比如thiserror.

为什么要用Result:

  • 可以强制程序员必须对可能出现的错误进行处理。
  • 也方便将错误向上传递(使用?,既方便也不会隐藏处理)
  • 函数的返回类型是Result也能表民其有可能出错。
  • 编译器会检查Result是否被处理,所以程序员不会忽略。
  • 因为Result是一个类型,所以可以把成功返回和错误返回放到一个集合里,方便统计。

常用的方法map,map_err