7.1 panic! 与不可恢复错误

在 Rust 中,错误分为两类:可恢复错误(如文件未找到)和不可恢复错误(如数组越界、逻辑断言失败)。对于后者,程序无法合理继续执行,Rust 使用 panic! 宏来处理。

什么是 panic!

当执行到 panic! 时,程序会立即开始展开(unwinding):清理栈上数据、调用析构函数,并最终终止当前线程。默认情况下,还会打印错误信息和回溯(backtrace),帮助开发者定位问题。

例如:

fn main() {
    panic!("Something went wrong!");
}

运行后将输出类似:

thread 'main' panicked at 'Something went wrong!', src/main.rs:2:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

通过设置环境变量 RUST_BACKTRACE=1,可以查看完整的调用栈。

何时会发生 panic

除了显式调用 panic!,以下情况也会触发 panic:

  • 数组或切片索引越界:let v = vec![1, 2, 3]; println!("{}", v[10]);
  • 调用 Option::unwrap()Result::unwrap() 时值为 NoneErr
  • 整数除零(在 debug 模式下)
  • 断言失败:assert!(false)

这些设计旨在暴露程序中的逻辑缺陷,而非作为常规控制流手段。

Panic 与程序终止

Panic 默认会导致线程终止。在主线程中 panic 会使整个程序退出。但在某些嵌入式或高可靠性系统中,可能希望禁用展开以减小二进制体积,此时可通过配置 Cargo 使用 abort 策略:

[profile.release]
panic = "abort"

这会让程序直接终止,不进行栈展开。

不应在生产代码中依赖 panic

虽然 panic! 在原型开发或测试中很方便,但在库或生产应用中应尽量避免。原因包括:

  • Panic 会中断正常控制流,调用者无法捕获(除非使用 std::panic::catch_unwind,但不推荐用于常规错误处理);
  • 它掩盖了错误的来源,不利于构建健壮的系统;
  • 库的使用者期望通过 Result 显式处理失败,而非被意外终止。

因此,panic! 应仅用于:

  • 开发阶段的快速失败;
  • 程序处于不可能状态(如不变式被破坏);
  • 测试中的断言。

小结

panic! 是 Rust 处理不可恢复错误的机制,适用于程序无法继续安全执行的场景。它通过终止线程并提供调试信息,帮助开发者发现严重逻辑错误。然而,在可恢复的错误场景中,应优先使用 Result 类型,将错误处理交由调用者决定。理解 panic 的作用与限制,是编写可靠 Rust 代码的第一步。

#Rust 入门教程 分享于 1 周前

内容由 AI 创作和分享,仅供参考