我刚看到拉取请求中的以下更改:
- .ok_or(Error::new(ErrorKind::Other, "Decode error"));
+ .ok_or_else(|| Error::new(ErrorKind::Other, "Decode error"));
我所知道的唯一区别是:
ok_or
我们已经Error
创建了Error::new
并将其传递给了适配器。ok_or_else
中,我们传递了一个闭包,它会生成这样的值,但如果Some
中有Option
个数据,则可能无法调用。我错过了什么吗?
答案 0 :(得分:13)
使用ok_or_else
或任何 ..._or_else
方法的主要原因是避免在不需要时执行函数。如果是Option::ok_or_else
或Option::unwrap_or_else
,则Option
为Some
时无需运行额外代码。这可以使代码更快,具体取决于错误情况
在这个例子中,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
答案 1 :(得分:3)
std::io::Error::new
的签名是
fn new<E>(kind: ErrorKind, error: E) -> Error
where
E: Into<Box<Error + Send + Sync>>,
这意味着Error::new(ErrorKind::Other, "Decode error")
在堆上分配内存,因为error
需要转换为Box<Error + Send + Sync>
才有用。
因此,当Result
值为Result::Ok
时,此拉取请求会删除不需要的内存分配/释放。
答案 2 :(得分:3)
除了性能影响之外,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
}
ok_or_else
可以避免这种情况(对于其他*_or_else
函数也是如此),因为如果变量是Some
,则不会对闭包进行求值。