Rust入门失败之Error Handling

Rust里的错误处理主要分两种: PanicResult

💀Panic

  • 不像C++的未定义操作, painc时的操作顺序:
    • 打印错误信息, 如果定义了RUST_BACKSTRACE=1, 还将打印堆栈;
    • 栈回溯, 按照堆栈顺序销毁资源, 所有类型(含自定义类型)的drop方法被调用;
    • 线程退出, Panic是线程级, 如果主线程崩了, 整个进程结束, 否则其它线程还会继续.
  • 可以用std::panic::catch_unwind()捕获panic时的stack unwinding, 这也是Rust test的做法.
  • 当C/C++等其它语言调用Rust代码时可以用std::panic::catch_unwind()捕获, 因为unwinding 非Rust code 的行为是未定义的.
  • std::panic::catch_unwind()只能用于恢复堆栈, 不要尝试着继续运行.
  • 如果清理过程中drop方法再次panic, 则Rust不会再尝试恢复堆栈unwind stack, 直接abort.

⚖️Result<T,E>

1
2
3
4
5
6
7
8
9
pub enum Result<T, E> {
/// Contains the success value
#[stable(feature = "rust1", since = "1.0.0")]
Ok(#[stable(feature = "rust1", since = "1.0.0")] T),

/// Contains the error value
#[stable(feature = "rust1", since = "1.0.0")]
Err(#[stable(feature = "rust1", since = "1.0.0")] E),
}

T, E 分别定义Ok和Err包含的类型:

  • Ok(T)
  • Err(E)
  • Result有两个方法: .as_ref().as_mut()分别把Result<T, E>转为 Result<&T, &E>Result<&mut T, &mut E>从而避免销毁它或者move.

  • fn remove_file(path: &Path) → Result<()>, 这里的Result是别名(aliases), 需要看对应的模块的public Result定义:

    1
    pub type Result<T> = result::Result<T, Error>
  • 通过println!("{:?}", err);可以查看到更多的技术性错误信息;

    • err.description()&str方式返回错误信息;
    • err.cause()返回Option<&Error>: 内部错误详细信息.
  • ?向上抛出Err, 只能用于返回Result的函数

  • errorchaincrate 可以用于定义error type, 方便 ?抛出不同类型Err

Custom Error Type

  • 通常直接定义错误信息结构体, 然后用Err()抛出就够了

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

    return Err(JsonError {...});
  • 如果希望和标准库的错误类型表现一致, 还需要定义fmt::DisplayError的trait.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    use std;
    use std::fmt;

    // Errors should be printable
    imple 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.
    impl std::error::Error for JsonError {
    fn description(&self) -> &str {
    &self.message
    }
    }