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

blu*_*e10 12 option rust

来自其他函数式语言(并且是Rust新手),我对Rust if let语法的动机感到有些惊讶.该RFC提到,如果没有if let,则"测试惯用的解决方案今天展开的Option<T>"或者是

match opt_val {
    Some(x) => {
        do_something_with(x);
    }
    None => {}
}
Run Code Online (Sandbox Code Playgroud)

要么

if opt_val.is_some() {
    let x = opt_val.unwrap();
    do_something_with(x);
}
Run Code Online (Sandbox Code Playgroud)

在Scala中,可以完全相同,但惯用的解决方案是map覆盖Option(或者foreach仅仅是为了副作用doing_something_with(x)).

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

opt_val.map(|x| do_something_with(x));
Run Code Online (Sandbox Code Playgroud)

Vla*_*eev 25

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

之前,if let只有这样,才能进行副作用上Option是匹配或ifOption::is_some()检查.match方法是最安全的方法,但它非常冗长,特别是当需要大量嵌套检查时:

match o1 {
    Some(v1) => match v1.f {
        Some(v2) => match some_function(v2) {
            Some(r) => ...
            None => {}
        }
        None => {}
    }
    None => {}
}
Run Code Online (Sandbox Code Playgroud)

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

if option.is_some()另一方面,方法略显冗长但仍然非常糟糕.它的条件检查unwrap()也没有静态绑定,所以如果没有编译器注意它就可能出错.

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

  • @bluenote10,我写 Scala 是为了谋生,所以我很清楚这一点:) 再次注意,`if let` 不仅适用于 `Option`*,而且语法可以说比闭包更轻量级. (2认同)

blu*_*uss 16

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

  • 注意:我接受这个答案,因为它简要总结了主要的 _technical_ 差异,但请参阅@Vladimir 的答案以获得更全面的解释。 (2认同)