|
|
|
@ -6,11 +6,43 @@
|
|
|
|
|
|
|
|
|
|
上面的问题在真实场景会经常遇到,其实处理起来挺复杂的,让我们先做一个假设:文件读取操作发生在系统启动阶段。那么可以轻易得出一个结论,一旦文件读取失败,那么系统启动也将失败,这意味着该失败是不可恢复的错误,无论是因为文件不存在还是操作系统硬盘的问题,这些只是错误的原因不同,但是归根到底都是不可恢复的错误(梳理清楚当前场景的错误类型非常重要)。
|
|
|
|
|
|
|
|
|
|
既然是不可恢复错误,那么一旦发生,只需让程序崩溃即可。对此,Rust 为我们提供了 `panic!` 宏,当调用执行该宏时,**程序会打印出一个错误信息,展开报错点往前的函数调用堆栈,最后退出程序**。
|
|
|
|
|
对于这些严重到影响程序运行的错误,触发 `panic` 是很好的解决方式。在 Rust 中触发 `panic` 有两种方式:被动触发和主动调用,下面依次来看看。
|
|
|
|
|
|
|
|
|
|
切记,一定是不可恢复的错误,才调用 `panic!` 处理,你总不想系统仅仅因为用户随便传入一个非法参数就崩溃吧?所以,**只有当你不知道该如何处理时,再去调用 panic!**.
|
|
|
|
|
|
|
|
|
|
## 调用 panic!
|
|
|
|
|
### 被动触发
|
|
|
|
|
先来看一段简单又熟悉的代码:
|
|
|
|
|
```rust
|
|
|
|
|
fn main() {
|
|
|
|
|
let v = vec![1, 2, 3];
|
|
|
|
|
|
|
|
|
|
v[99];
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
心明眼亮的同学立马就能看出这里发生了严重的错误 —— 数组访问越界,在其它编程语言中无一例外,都会报出严重的异常,甚至导致程序直接崩溃关闭。
|
|
|
|
|
|
|
|
|
|
而 Rust 也不例外,运行后将看到如下报错:
|
|
|
|
|
```shell
|
|
|
|
|
$ cargo run
|
|
|
|
|
Compiling panic v0.1.0 (file:///projects/panic)
|
|
|
|
|
Finished dev [unoptimized + debuginfo] target(s) in 0.27s
|
|
|
|
|
Running `target/debug/panic`
|
|
|
|
|
thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 99', src/main.rs:4:5
|
|
|
|
|
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
上面给出了非常详细的报错信息,包含了具体的异常描述以及发生的位置,甚至你还可以加入额外的命令来看到异常发生时的堆栈信息,这个会在后面详细展开。
|
|
|
|
|
|
|
|
|
|
总之,类似的 `panic` 还有很多,而被动触发的 `panic` 是我们日常开发中最常遇到的,这也是 Rust 给我们的一种保护,毕竟错误只有抛出来,才有可能被处理,否则只会偷偷隐藏起来,寻觅时机给你致命一击。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 主动调用
|
|
|
|
|
|
|
|
|
|
在某些特殊场景中,开发者想要主动抛出一个异常,例如开头提到的在系统启动阶段读取文件失败。
|
|
|
|
|
|
|
|
|
|
对此,Rust 为我们提供了 `panic!` 宏,当调用执行该宏时,**程序会打印出一个错误信息,展开报错点往前的函数调用堆栈,最后退出程序**。
|
|
|
|
|
|
|
|
|
|
切记,一定是不可恢复的错误,才调用 `panic!` 处理,你总不想系统仅仅因为用户随便传入一个非法参数就崩溃吧?所以,**只有当你不知道该如何处理时,再去调用 panic!**.
|
|
|
|
|
|
|
|
|
|
首先,来调用一下 `panic!`,这里使用了最简单的代码实现,实际上你在程序的任何地方都可以这样调用:
|
|
|
|
|
|
|
|
|
|