在 Rust 中使用 unwrap() 是可以的。

这是一篇关于 Rust 语言中错误处理的博客文章,主要讨论了unwrap()的使用场景、 panic 的含义及作用、错误处理的方式等内容,具体如下:

  • 立场阐述:在应用和库中不应将 panic 用于错误处理;在原型开发、测试、基准测试和文档示例中使用 panic 进行错误处理可能是可以接受的;Rust 程序 panic 表示程序中有 bug;可以将 blame 分配给 panic 的责任方;无法将所有不变量都移入类型系统时,对于运行时不变量有几种选择;在某些情况下可以使用unwrap()expect()等;更倾向于使用expect(),但在expect()会产生噪音时使用unwrap()
  • unwrap()介绍unwrap()是定义在Option<T>Result<T, E>上的方法,分别在SomeOk变体时返回底层的T,否则 panic。其目的是解决是否以及在多大程度上使用unwrap()的问题。
  • panic 的含义:panic 发生时,进程可能会终止或进行栈展开,如果栈展开未被捕获,程序将终止并打印 panic 消息和源信息;可以捕获 panic 并进行处理,如在 Web 服务器和测试 harness 中;panic 对于程序员调试很有用,但对终端用户不太友好。
  • 错误处理介绍:Rust 中有多种处理错误的方式,如以非零退出码终止、panic 或使用Result<T, E>处理正常值;anyhow crate 可轻松为错误值添加上下文;在 Rust 中,将错误作为值处理(使用Result<T, E>)通常被视为最佳实践,标准库和核心生态库都使用这种方式。
  • unwrap()是否应用于错误处理:在一些场景下常见使用unwrap(),如快速一次性程序、测试和文档示例;个人对于在这些场景中使用unwrap()没有强烈意见,但认为在 Rust 库或应用中不应使用unwrap()进行错误处理,因其会导致不良的用户体验;另外,unwrap()在某些程序员临时用于解决问题后会被删除并添加“ proper ”错误处理。
  • 可恢复与不可恢复错误:Rust 书籍中“Error Handling”章节提出将错误分为可恢复和不可恢复,但作者认为这种概念化没有帮助,应根据具体情况确定是将错误作为值处理还是作为 panic 处理,如用户指定路径的文件未打开是错误,而程序从静态字符串字面量构建正则表达式出错则应 panic。
  • 是否永远不应 panic:一般来说,正确的 Rust 程序不应 panic;对于快速的 Rust“脚本”中使用 panic 进行错误处理,这是否正确存在争议,可视为有标记为wontfix的 bug。
  • 是否永远不应使用unwrap()expect()unwrap()expect()只有在值不符合调用者预期时才会 panic,如果值总是符合预期则不会 panic;很多关于unwrap()的困惑来自于人们对其使用的误解,实际上是关于是否将 panic 作为错误处理策略的问题。
  • 运行时不变量:运行时不变量是在运行时应始终为真的保证,可通过不同方式设置,如使用std::num::NonZeroUsize在编译时保证,或使用Option<usize>在运行时由调用者保证。
  • 为何不将所有不变量都设为编译时不变量:有时无法将所有不变量都移至编译时,有时是因为 API 复杂性,如aho-corasick crate 中的示例,通过在运行时进行检查和 panic 可以保持 API 的简单性,避免引入过多的类型和复杂性。
  • 当不变量无法移至编译时:以确定性有限自动机(DFA)的搜索实现为例,由于输入可能是任意正则表达式,无法将 DFA 构建和搜索的不变量推至编译时,必须在运行时维护,若 panic 发生则意味着代码存在 bug。
  • 为何不返回错误而不是 panic:将错误作为返回值处理可以避免 panic,但会使代码更复杂,文档更混乱,这种编码风格在高可靠性领域可能有一定价值,但会限制使用标准库和核心生态库,且难以正确记录错误条件。
  • 何时应使用unwrap()即使不是必要的:以regex-syntax crate 中的示例为例,有时使用unwrap()可以使代码更简单,虽然可以避免使用unwrap(),但改写后的代码更复杂,在明显可以判断unwrap()不会 panic 的情况下,使用unwrap()更合适。
  • 为何不使用expect()而使用unwrap()expect()unwrap()的基础上添加了额外的上下文信息到 panic 消息中,但消息往往较短,且不一定包含使用expect()正确的全部理由;在某些情况下,使用expect()会增加代码的噪音,应根据具体情况判断使用unwrap()还是expect()
  • 是否应针对unwrap()的使用进行 lint:反对对unwrap()的使用进行 lint 的观点包括:很多expect()的使用会增加代码噪音;unwrap()是 idiomatic 的,在标准库和核心生态库中广泛使用;还有很多其他可能 panic 的常见情况无法通过 lint 禁止;禁止unwrap()可能导致人们使用更无意义的expect("");虽然不能完全反对 lint,但认为其带来的好处不足以抵消负面影响。
  • panic 为何如此重要:panic 是 bug 常常不需要在调试器中运行 Rust 程序的原因之一,它提供栈跟踪和行号,对于终端用户也很有用,可轻松获取完整栈跟踪;应在合适的地方使用 panic,如使用assert!检查前提条件和运行时不变量,使用expect()添加上下文,使用unwrap()避免噪音等;将运行时不变量推至编译时不变量通常是更好的选择,但有时无法或不适合这样做。
阅读 17
0 条评论