【问题标题】:When should we use unwrap vs expect in Rust我们什么时候应该在 Rust 中使用 unwrap 和 expect
【发布时间】:2020-04-19 08:37:13
【问题描述】:

我是 rust 新手,并试图了解我们何时应该使用 unwrap 和 expect。

这是一个示例代码:

use std::env;

fn main() {
    let args: Vec<String> = env::args().collect();

    let query = args.get(1).unwrap();
    println!("query from unwrawp: {}", query);

    let query = args.get(1).expect("insufficient arguments");
    println!("query from expect: {}", query);

    //$ cargo run hello
    //OUTPUT:
    //query from expect: hello
    //query from unwrawp: hello

}

我观察到的唯一区别是预期中有一条自定义的恐慌消息。
这两个是可以互换的,还是有什么特殊的场景我们应该使用一个而不是另一个?

【问题讨论】:

  • 据我所知,它们是可以互换的。我通常使用unwrap,如果逻辑100% 清楚不会发生故障,如果有可能出现我没有考虑过的边缘情况——或者可能触发的情况,我会使用expect通过不正确的开发人员编写的配置文件等。
  • answer 很好地概述了在选择一种或另一种时要考虑的错误模式。简而言之,unwrap() 是一种在可恢复错误和不可恢复错误之间进行转换的方法。另一方面,当您调用expect() 时,您假设已经处于不可恢复的错误状态。我想指导原则应该是:如果您无法从失败的 unwrap() 调用中恢复,请选择 expect() 并让您的诊断包含更好的错误消息。
  • @IInspectable:我认为您误读了您链接的答案。 unwrapexpect 都从可恢复转换为不可恢复,唯一的区别是一个指定自定义错误消息,另一个不指定。
  • @mat:我想我误解了我的观点。 unwrap()expect() 都将 panic!(),当没有什么可以打开时。在这方面,它们是相同的。这是您的代码所处的情况,这会有所不同。如果没有展开的值,您的代码无法有意义地继续,请选择expect()。如果您可以回应没有值,请在验证值存在后选择unwrap()。在这种情况下,unwrap() 只会在您的代码出现问题时panic!() 才会从可恢复状态转变为不可恢复状态。
  • 这两个选项都引入了一个函数。唯一的区别在于他们的名字。这并没有改变假设需要unwrap() 和其他东西的事实。其他东西被命名为expect()。特定的名称不如不同的属性重要。这使您可以向代码的读者传达不同的语义。

标签: rust


【解决方案1】:

Rust 没有function overloading,所以应该有办法声明“unwrap with a message”,那就是expect

  1. expect == unwrap 带消息
  2. expect_err == unwrap_err 带消息

关于“unwrap vs expect”的使用场景Rust Book (Ch 9) 说:

使用 expect 代替 unwrap 并提供良好的错误消息可以传达您的意图并更容易追踪恐慌的根源。 因为此错误消息以我们指定的文本开头...将更容易在代码中找到此错误消息的来源。

【讨论】:

  • FWIW,除了函数重载,同样可以使用可选参数来实现,而 Rust 也没有。
【解决方案2】:

Alexander Fadeev's answer 是正确的,但Rust Book (Ch 9) 提供了更多信息:

当您有一些其他逻辑可以确保Result 将具有Ok 值时,调用unwrap 也是合适的,但编译器无法理解该逻辑。您仍然需要处理 Result 值:您调用的任何操作通常仍然有可能失败,即使在您的特定情况下逻辑上是不可能的。如果您可以通过手动检查代码来确保您永远不会有Err 变体,那么调用unwrap 是完全可以接受的。这是一个例子:

use std::net::IpAddr;

let home: IpAddr = "127.0.0.1".parse().unwrap();

我们通过解析一个硬编码的字符串来创建一个IpAddr 实例。我们可以看到127.0.0.1 是一个有效的IP 地址,所以这里可以使用unwrap。但是,硬编码的有效字符串不会改变parse 方法的返回类型:我们仍然会得到Result 值,编译器仍然会让我们处理Result,就像处理Err 变体一样是一种可能性,因为编译器不够聪明,无法看到该字符串始终是有效的 IP 地址。如果 IP 地址字符串来自用户而不是硬编码到程序中,因此确实存在失败的可能性,我们肯定希望以更健壮的方式处理 Result

因此,如果您知道错误永远不会发生,但编译器希望您处理错误,unwrap 比使用 expect 时需要提供自定义且不必要的错误消息更简洁、更短。

【讨论】:

    猜你喜欢
    • 2021-09-07
    • 1970-01-01
    • 2012-11-24
    • 2015-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-04
    相关资源
    最近更新 更多