我应该在生产应用程序中避免打包吗?
这很容易在运行时用unwrap
崩溃:我应该在生产应用程序中避免打包吗?
fn main() {
c().unwrap();
}
fn c() -> Option<i64> {
None
}
结果:
Compiling playground v0.0.1 (file:///playground)
Running `target/debug/playground`
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', ../src/libcore/option.rs:325
note: Run with `RUST_BACKTRACE=1` for a backtrace.
error: Process didn't exit successfully: `target/debug/playground` (exit code: 101)
是unwrap
只专为快速测试和证明的概念?
我不能肯定“我的程序不会崩溃这里,这样我就可以使用unwrap
”如果我真的想避免panic!
在运行时,我想避免panic!
就是我们要在生产中的应用。
换句话说,如果我使用unwrap
,可以说我的程序是可靠的吗?或者我必须避免unwrap
,即使案件看起来很简单?
我读this答案:
,当你正确保您没有错误这是最好的使用。
但我不认为我可以“肯定地确定”。
我不认为这是一个意见问题,而是一个关于Rust核心和编程的问题。
虽然整个“错误处理” - 主题非常复杂且通常以意见为基础,但这个问题实际上可以在这里得到解答,因为Rust的理念相当狭隘。那就是:
-
panic!
为编程错误(“错误”) - 正确的错误传播,并与
Result<T, E>
处理和Option<T>
为预期和可恢复错误
我们可以把unwrap()
as 转换这两种错误之间(它我s将可恢复的错误转换为panic!()
)。当你写在你的程序unwrap()
,你说:
在这一点上,一个
None
/Err(_)
值是编程错误和程序无法从中恢复。
例如,假设你是一个HashMap
工作,要插入您可能希望稍后变异值:
age_map.insert("peter", 21);
// ...
if /* some condition */ {
*age_map.get_mut("peter").unwrap() += 1;
}
这里我们使用unwrap()
,因为我们可以确保密钥保存一个值。如果没有,甚至更重要的话,这将是一个编程错误:它不是真正可以恢复的。在那时,你会怎么做,关键是"peter"
没有价值?尝试再次插入...?
但是你可能知道,Rust的标准库中的地图有一个美丽的entry
API。有了这个API,你可以避免所有那些unwrap()
。这适用于几乎所有情况:您可以经常重构您的代码以避免unwrap()
!只有在极少数情况下,它才是无法解决的。但是如果你想发出信号就可以使用它:在这一点上,这将是一个编程错误。
已经有上的“错误处理”,其结论是类似铁锈的哲学话题最近,相当受欢迎的博客文章。这是相当长的,但值得一读:“The Error Model”。这里是我的总结文章中关于这个问题的尝试:
- 的编程错误和恢复的错误。
- 之间刻意区分使用“快速失败”编程错误的做法
总之:使用unwrap()
当你确定可恢复的错误,你得到的其实是在这一点上不可恢复的。受影响的线路;-)
轰隆,超级清晰!我仔细阅读并了解了很多!我会牢记这一点:“你可以经常重构代码以避免解包()!” –
如果它只提到一个'expect()',我会给它+1。 – mcarton
我宁愿他用'expect(“”)'来表示他在字符串中所期望的内容,而不是'unwrap()',说明上面评论中期望的内容! –
unwrap()
不一定危险。与unreachable!()
一样,有些情况下您可以确定某些情况不会被触发。
函数返回Option
或Result
有时仅适用于更广泛的条件,但由于您的程序结构如何,这些情况可能永远不会发生。
例如:当您从Vec
创建一个迭代符你打造专业化自己,你知道它的确切长度,可以肯定调用next()
多久就返回一个Some<T>
(你可以安全地unwrap()
它)。
我个人认为'unwrap()'是危险的,因为'unwrap()'取决于之前编写的代码,所以编辑代码时需要非常小心,另外,你可能知道一些'unwrap()'可能是安全的,但是你*我认为如果你已经写了'unwrap()',最好是发表评论'//safe'在这些行中,我这样做是为了检查我使用'grep'打开多少个解包。 –
这些条件在将来可能会或可能不会改变。我不是说这是一条规则 - 这完全可能。 – ljedrz
换句话说以上评论解释“为什么?”加分,我可以说,我的计划是可靠的,如果我使用展开?或者即使案件看起来很简单,我是否也必须避免拆包?
我认为使用unwrap
明智地是你必须学会处理,它不能被避免。
我反问攻势将是:
- 我可以说我的程序是可靠的,如果我使用的载体,数组或切片索引?
- 如果我使用整数除法,我可以说我的程序是可靠的吗?
- 如果我添加数字,我可以说我的程序是可靠的吗?
(1)就像拆开包装,索引恐慌,如果你犯了一个违反合同并尝试为出界。这将是该程序中的一个错误,但它不像调用unwrap
那样引起太多关注。 (2)如果除数为零,则类似于展开,整数除法恐慌。 (3)与unwrap不同,加法不检查发布版本中的溢出,因此它可能会静默地导致环绕和逻辑错误。
当然,还有一些策略可以处理所有这些,而不会在代码中留下恐慌的情况,但许多程序仅仅用于例如边界检查。
有折叠成一个这里有两个问题:
- 是在生产过程中使用的
panic!
接受 - 在生产
panic!
使用unwrap
接受的是一种工具,是在Rust中用于表示无法恢复的情况/违反的假设。它可以用于崩溃一个程序,这个程序在面对这种故障时不可能继续(例如,OOM的情况),或者在知道它不能执行的时候解决编译器(目前)。
unwrap
是一种方便,在生产中最好避免。关于unwrap
的问题是,它没有说明哪个假设被违反,最好使用expect("")
,它在功能上是等价的,但也会提供关于哪里出错的线索(无需打开源代码)。
* Crash *是一个可怕的滥用词现今国际海事组织;人们甚至在有例外的语言中将它用于未处理的异常。例如,对程序的恐慌远没有segfault那么糟糕。恐慌是故意说“程序的状态是*错误*,我现在就停下来,没有两种方式。 – Shepmaster
@Shepmaster好吧,谢谢你的这些精度! –