我应该避免在生产应用程序中打开包装吗?

时间:2016-09-13 19:33:02

标签: error-handling rust

使用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仅用于快速测试和概念验证吗?

我无法确认&#34;我的程序不会在这里崩溃,所以我可以使用unwrap&#34;如果我真的想在运行时避免panic!,我认为在生产应用程序中我们想要避免panic!

换句话说,如果我使用unwrap,我可以说我的程序是可靠的吗?或者,即使案件看起来很简单,我也必须避免unwrap吗?

我看了this回答:

  

最好在您确定没有错误时使用。

但我不认为自己可以确信&#34;。

我不认为这是一个意见问题,而是一个关于Rust核心和编程的问题。

5 个答案:

答案 0 :(得分:23)

虽然整个“错误处理” - 主题非常复杂并且经常以意见为基础,但这个问题实际上可以在这里得到解答,因为Rust有相当狭隘的哲学。那就是:

  • panic! 编程错误(“错误”)
  • 针对预期和可恢复错误的Result<T, E>Option<T>进行适当的错误传播和处理

可以将unwrap()视为转换这两种错误(它将可恢复的错误转换为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() !只有极少数情况下才有办法解决。但是如果你想发出信号就可以使用它了:在这一点上,这将是一个编程错误。

最近有一篇关于“错误处理”主题的相当受欢迎的博客文章,其结论类似于Rust的哲学。它很长但值得一读:“The Error Model”。以下是我总结与此问题相关的文章:

  • 故意区分编程错误可恢复错误
  • 使用“快速失败”方法编写错误

总结:当您确定所获得的可恢复的错误实际上不可恢复时,请使用unwrap()点。在受影响的线上方的评论中解释“为什么?”的奖励积分;-)

答案 1 :(得分:5)

  

换句话说,如果我使用unwrap,我可以说我的程序是可靠的吗?或者即使案件看起来很简单,我也必须避免打开包裹吗?

我认为明智地使用unwrap是你必须学会​​处理的东西,它是不可避免的。

我的修辞问题是:

  1. 如果我在矢量,数组或切片上使用索引,我可以说我的程序是可靠的吗?
  2. 如果我使用整数除法,我可以说我的程序是可靠的吗?
  3. 如果我添加数字,我可以说我的程序是可靠的吗?
  4. (1)就像解包,索引恐慌,如果你犯了合同违规并尝试索引越界。这可能是程序中的一个错误,但它并没有像调用unwrap一样受到关注。

    如果除数为零,

    (2)就像解包,整数除法恐慌。

    (3)与unwrap不同,add不会检查发布版本中的溢出,因此它可能会无声地导致环绕和逻辑错误。

    当然,有一些策略可以处理所有这些,而不会在代码中留下恐慌的情况,但许多程序只是简单地使用边界检查。

答案 2 :(得分:3)

这里有两个问题:

  • 是生产中可接受的panic!的使用
  • 是生产中可接受的unwrap的使用

panic!是一个工具,在Rust中用于表示不可恢复的情况/违反的假设。它可以用来崩溃一个在面对这个失败时无法继续运行的程序(例如,OOM情况),或者解决编译器知道它无法执行(目前)。

unwrap是一种便利,最好在生产中避免使用。关于unwrap的问题在于它没有说明违反了哪个假设,最好使用功能相同的expect(""),但也会给出错误的线索(不打开源代码)码)。

答案 3 :(得分:2)

unwrap()不一定是危险的。与unreachable!()一样,有些情况下您可以确定某些条件不会被触发。

返回OptionResult的函数有时只适用于更广泛的条件,但由于程序结构的原因,这些情况可能永远不会发生。

例如:当您从Vec创建一个迭代器时,您知道它的确切长度,并且可以确定在其上调用next()多长时间会返回Some<T>(你可以安全地unwrap()它。

答案 4 :(得分:-2)

展开对于原型制作非常有用,但对于生产而言并不安全。完成初始设计后,您可以返回并将import multiprocessing as mp import numpy as np def foo(p): global i return p*i global lower, upper lower = 1 upper = 4 for i in range(lower, upper): if __name__ == '__main__': dataset = np.linspace(1, 100, 100) agents = mp.cpu_count() - 1 chunksize = 5 pool = mp.Pool(processes=agents) result = pool.map(foo, dataset, chunksize) print result print i pool.close() pool.join() 替换为unwrap()