为什么我更喜欢`Option :: ok_or_else`而不是`Option :: ok_or`?

Vic*_*voy 7 rust

我刚看到拉取请求中的以下更改:

- .ok_or(Error::new(ErrorKind::Other, "Decode error"));
+ .ok_or_else(|| Error::new(ErrorKind::Other, "Decode error"));
Run Code Online (Sandbox Code Playgroud)

我所知道的唯一区别是:

  1. ok_or我们已经创建ErrorError::new,并通过它变成一个适配器.
  2. ok_or_else我们已经传递了一个闭包,它会产生这样一个值,但是如果有Some数据则可能不会被调用Option.

我错过了什么吗?

She*_*ter 14

主要原因使用ok_or_else任何..._or_else方法是避免在执行一个函数的不需要的时候.在的情况下,Option::ok_or_else或者Option::unwrap_or_else,有没有必要运行额外的代码时OptionSome.这可以使代码更快,具体取决于错误情况中发生的情况

在这个例子中,Error::new可能执行分配,但它也可以写入标准输出,发出网络请求,或任何Rust代码可以做的任何事情; 从外面很难说出来.将这些代码放在闭包中通常更安全,因此在成功案例发生时您不必担心无关的副作用.

Clippy也为你提供了这个:

warning: use of `unwrap_or` followed by a function call
 --> src/main.rs:3:15
  |
3 |     let foo = foo.unwrap_or("hello".to_string());
  |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `foo.unwrap_or_else(|| "hello".to_string())`
  |
  = note: #[warn(or_fun_call)] on by default
  = help: for further information visit https://github.com/Manishearth/rust-clippy/wiki#or_fun_call
Run Code Online (Sandbox Code Playgroud)

  • 好的,但是您还能说出哪些情况适合“unwrap_or”和“unwrap_or_else”以及其他情况吗?我知道有些情况是当您将它们与标量一起使用时,例如“unwrap_or(0)”,但仅此而已? (2认同)

lje*_*drz 6

除了性能影响之外,ok_or如果不够小心,更复杂的参数可能会产生意想不到的结果。考虑以下情况:

fn main() {
    let value: Option<usize> = Some(1);

    let result = value.ok_or({ println!("value is not Some!"); 0 }); // actually, it is

    assert_eq!(result, Ok(1)); // this holds, but "value is not Some!" was printed
}
Run Code Online (Sandbox Code Playgroud)

这本来可以避免ok_or_else(其他*_or_else函数也是如此),因为如果变体是Some.

  • @Shepmaster,它把重点放在了不同的事情上 - 你的答案的最初形状听起来主要是面向性能的,并且可能的误导性结果对于浏览的读者来说可能并不明显。 (2认同)