• Result::ok_or()和Result::ok_or_else()方法的区别
  • 发布于 2个月前
  • 351 热度
    0 评论
  • 猫千千
  • 0 粉丝 23 篇博客
  •   
考虑下面的代码:
use std::collections::HashMap;

fn lookup(map: &HashMap<String, i32>, key: &str) -> Result<i32, String> {
    map.get(key).copied().ok_or(format!("key {} not found", key))
}

fn main() {
    let mut map = HashMap::new();
    map.insert("x".to_string(), 1);
    assert_eq!(lookup(&map, "x"), Ok(1));
    assert_eq!(lookup(&map, "y"), Err("key y not found".to_string()));
}
你能发现代码中的任何问题吗?如果找不到问题,让我们来看一些提示:比起即刻求值,更喜欢惰性求值。

在大多数编程语言中,函数的参数在传递给函数之前都会被求值。这意味着,无论Option是Some还是None,都会对Option::ok_or()的参数求值。在我们的例子中,它是format!(…)宏,这是相当昂贵的,因为它需要动态地为字符串分配内存。

换句话说,我们直接调用format!(…)宏,而不考虑Option的值,这是即刻求值。当Option为Some时,这是浪费和不必要的,使lookup()函数效率低下。为了提高效率,我们可以使用if let Some()…else语句,或者使用Result::ok_or_else()方法。
fn lookup(map: &HashMap<String, i32>, key: &str) -> Result<i32, String> {
    // map.get(key).copied().ok_or(format!("key {} not found", key))
    map.get(key).copied().ok_or_else(|| format!("key {} not found", key))
}
Result::ok_or()和Result::ok_or_else()方法的区别在于,前者是即刻求值,而后者是惰性求值。为了实现延迟求值,它必须接受函数或闭包作为参数,而不是一个值。

Rust中还有很多这样的变体,比如Result::or() / Result::or_else()或者Option::or()  / Option::or_else()。通常,这些惰性版本通常都会在后面添加一个_else后缀。更重要的是,如果参数是一个值,则必须立即的求值,而如果它是一个函数,则可以惰性的求值。

用户评论