为什么Rust需要`if let`语法?

时间:2014-12-17 20:33:36

标签: option rust

来自其他功能语言(并且是Rust新手),我对Rust if let语法的动机感到有些惊讶。 RFC提及没有if let,今天的惯用解决方案,用于测试和展开Option<T>&#34;是

match opt_val {
    Some(x) => {
        do_something_with(x);
    }
    None => {}
}

if opt_val.is_some() {
    let x = opt_val.unwrap();
    do_something_with(x);
}

在Scala中,可以完全相同,但惯用的解决方案是map而不是Option(或foreach,如果它仅用于侧面doing_something_with(x))的效果。

为什么在Rust中做同样的事情并不是惯用的解决方案?

opt_val.map(|x| do_something_with(x));

4 个答案:

答案 0 :(得分:19)

map()用于转换可选值,而if let主要用于执行副作用。虽然Rust不是纯语言,但是它的任何代码块都可以包含副作用,因此映射语义仍然存在。使用map()执行副作用虽然可能,但只会让读者感到困惑。请注意,它不应该有性能损失,至少在简单的代码中 - LLVM优化器完全能够将闭包直接内联到调用函数中,因此它转而等同于match语句。

if let之前,对Option执行副作用的唯一方法是匹配或if进行Option::is_some()检查。 match方法是最安全的方法,但它非常冗长,特别是当需要大量嵌套检查时:

match o1 {
    Some(v1) => match v1.f {
        Some(v2) => match some_function(v2) {
            Some(r) => ...
            None => {}
        }
        None => {}
    }
    None => {}
}

注意突出的向右漂移和许多语法噪音。如果分支不是简单匹配,而是具有多个语句的适当块,则情况会变得更糟。

另一方面,

if option.is_some()方法略显冗长但仍然读得非常糟糕。此外,它的条件检查和unwrap()不是静态绑定的,所以如果编译器没有注意到它就可能出错。

if let基于与match相同的模式匹配基础结构解决了详细程度问题(因此它比if option.is_some()更难出错),并且作为附带好处,允许使用模式中的任意类型,而不仅仅是Option。例如,某些类型可能不提供类似map()的方法; if let仍然可以很好地与他们合作。所以if let是明显的胜利,因此它是惯用的。

答案 1 :(得分:14)

.map()特定于Option<T>类型,但if let(和while let!)是适用于所有Rust类型的功能。

答案 2 :(得分:1)

因为你的解决方案创建了一个使用资源的闭包,而if let完全取决于你的第一个例子,而不是。我也发现它更具可读性。

Rust是关于零成本抽象的,它使编程更好,if letwhile let就是很好的例子(至少IMO - 我意识到这是个人偏好的问题)。它们不是绝对必要的,但它们确实使用起来很好(另见:Clojure,它们可能会被取消)。

答案 3 :(得分:0)

a related issue The Rust Programming Language 的引用:

  

您最好将out = subprocess.check_output(["git", "remote","-v"]), stderr=subprocess.STDOUT) 视为单手if let,而无需执行详尽的检查。它通常与matchif无关,这就是为什么它如此混乱的原因。 :)

     

也许最好重命名整个运算符,将其命名为let或类似的名称。

(稍加修改即可在没有上下文的情况下变得有意义)