有没有什么好的情况我们应该使用“unwrap”?

Web*_*rix 1 rust unwrap

由于使用unwrap可能会出现问题,因为它在错误场景中崩溃,因此可能被认为是危险的使用。

如果我百分百确定它不会崩溃怎么办,就像在以下场景中一样:

if option.is_some() {
    let value = option.unwrap();
}
Run Code Online (Sandbox Code Playgroud)
if option.is_some() {
    let value = option.unwrap();
}
Run Code Online (Sandbox Code Playgroud)

由于我们已经检查过,Result因此Option使用时不会发生崩溃unwrap()。但是,我们可以使用matchor if let。在我看来,要么match要么if let用法更优雅。

Séb*_*uld 5

让我们重点关注Result;我会回到Option最后。

的目的Result是发出信号,该结果可能成功,也可能因错误而失败。因此,它的任何使用都应该属于这一类。让我们忽略箱子Result因不可能失败的操作而返回的情况。

通过做你正在做的事情(检查if result.is_ok() 然后提取值),你实际上是在做同样的事情两次。第一次,您正在检查 的内容Result,第二次,您正在不安全地检查和提取。

match这确实可以用或 来完成map,并且两者都比 更惯用if。考虑一下这个例子:

您有一个实现以下特征的对象:

use std::io::{Error, ErrorKind};

trait Worker {
    fn hours_left(&self) -> Result<u8, Error>;
    fn allocate_hours(&mut self, hours: u8) -> Result<u8, Error>;
}
Run Code Online (Sandbox Code Playgroud)

我们假设hours_left()它的作用与罐头上的说明完全一致。我们还假设我们有一个可变的借用Worker。让我们实施一下allocate_hours()

为此,我们显然需要检查我们的员工是否还有剩余时间可供分配。你可以像你的那样写:

fn allocate_hours(&mut self, hours: u8) {
    let hours_left = self.hours_left();
    if (hours_left.is_ok()) {
        let remaining_hours = hours_left.unwrap();
        if (remaining_hours < hours) {
            return Err(Error::new(ErrorKind::NotFound, "Not enough hours left"));
        }
    // Do the actual operation and return
    } else {
        return hours_left;
    }
}
Run Code Online (Sandbox Code Playgroud)

然而,这种实现方式既笨重又低效。我们可以通过完全避免unwrapandif语句来简化这一点。

fn allocate_hours(&mut self, hours: u8) -> Result<u8, Error> {
    self.hours_left()
        .and_then(|hours_left| {
            // We are certain that our worker is actually there to receive hours
            // but we are not sure if he has enough hours. Check.
            match hours_left {
                x if x >= hours => Ok(x),
                _ => Err(Error::new(ErrorKind::NotFound, "Not enough hours")),
            }
        })
        .map(|hours_left| {
            // At this point we are sure the worker has enough hours.
            // Do the operations
        })
}
Run Code Online (Sandbox Code Playgroud)

我们在这里用一石打死了多只鸟。我们使代码更具可读性、更易于遵循,并且删除了一大堆重复操作。这也开始看起来像 Rust,而不像 PHP ;-)

Option类似并且支持相同的操作。如果您想相应地处理OptionorResult和分支的内容,并且您正在使用unwrap,那么当您忘记打开某些东西时,您将不可避免地陷入许多陷阱。

在某些真实的情况下,你的程序应该会崩溃。对于那些,请考虑expect(&str)unwrap()

  • unwrap 肯定不会被广泛认为是代码异味。 (3认同)
  • 是的,我知道那个医生说什么。我写的。文档中该部分的重点是特别说明在某些情况下展开是可以的。我特别对你的说法提出异议,即它被广泛认为是一种代码味道。但事实并非如此。当它用于错误处理时,它只是一种代码味道,这是一个重要的限定。此外,医生并没有说“当你无法恢复时没关系”,这不太可行。相反,更简单的说法是,如果最终用户观察到恐慌,则代码中的某个位置存在错误。 (2认同)