ifif let表达式

if-expr.md
commit: d23f9da8469617e6c81121d9fd123443df70595d
本章译文最后维护日期:2021-5-6

if表达式

句法
IfExpression :
   if Expression排除结构体表达式 BlockExpression
   (else ( BlockExpression | IfExpression | IfLetExpression ) )?

if表达式是程序控制中的一个条件分支。if表达式的句法是一个条件操作数(operand)后紧跟一个块,再后面是任意数量的 else if条件表达式和块,最后是一个可选的尾部 else块。 条件操作数的类型必须是布尔型。如果条件操作数的求值结果为 true,则执行紧跟的块,并跳过后续的 else if块或 else块。 如果条件操作数的求值结果为 false,则跳过紧跟的块,并按顺序求值后续的 else if条件表达式。 如果所有 if条件表达式和 else if条件表达式的求值结果均为 false,则执行 else块。 if表达式的求值结果就是所执行的块的返回值,或者如果没有块被求值那 if表达式的求值结果就是 ()if表达式在所有情况下的类型必须一致。

#![allow(unused)]
fn main() {
let x = 3;
if x == 4 {
    println!("x is four");
} else if x == 3 {
    println!("x is three");
} else {
    println!("x is something else");
}

let y = if 12 * 15 > 150 {
    "Bigger"
} else {
    "Smaller"
};
assert_eq!(y, "Bigger");
}

if let表达式

句法
IfLetExpression :
   if let Pattern = Expression排除结构体表达式和惰性布尔运算符表达式 BlockExpression
   (else ( BlockExpression | IfExpression | IfLetExpression ) )?

if let表达式在语义上类似于 if表达式,但是代替条件操作数的是一个关键字 let,再后面是一个模式、一个 = 和一个检验对象(scrutinee)操作数。 如果检验对象操作数的值与模式匹配,则执行相应的块。 否则,如果存在 else块,则继续处理后面的 else块。和 if表达式一样,if let表达式也可以有返回值,这个返回值是由被求值的块确定。

#![allow(unused)]
fn main() {
let dish = ("Ham", "Eggs");

// 此主体代码将被跳过,因为该模式被反驳
if let ("Bacon", b) = dish {
    println!("Bacon is served with {}", b);
} else {
    // 这个块将被执行。
    println!("No bacon will be served");
}

// 此主体代码将被执行
if let ("Ham", b) = dish {
    println!("Ham is served with {}", b);
}

if let _ = 5 {
    println!("不可反驳型的模式总是会匹配成功的");
}
}

if表达式和 if let表达式能混合使用:

#![allow(unused)]
fn main() {
let x = Some(3);
let a = if let Some(1) = x {
    1
} else if x == Some(2) {
    2
} else if let Some(y) = x {
    y
} else {
    -1
};
assert_eq!(a, 3);
}

if let表达式等价于match表达式,例如:

if let PATS = EXPR {
    /* body */
} else {
    /*else */
}

is equivalent to

match EXPR {
    PATS => { /* body */ },
    _ => { /* else */ },    // 如果没有 else块,这相当于 `()`
}

可以使用操作符 | 指定多个模式。 这与匹配(match)表达式中的 | 具有相同的语义:

#![allow(unused)]
fn main() {
enum E {
    X(u8),
    Y(u8),
    Z(u8),
}
let v = E::Y(12);
if let E::X(n) | E::Y(n) = v {
    assert_eq!(n, 12);
}
}

if let表达式不能是惰性布尔运算符表达式。 使用惰性布尔运算符的效果是不明确的,因为 Rust 里一个新特性(if-let执行链(if-let chains)的实现-请参阅eRFC 2947)正被提上日程。 当确实需要惰性布尔运算符表达式时,可以像下面一样使用圆括号来实现:

// Before...
if let PAT = EXPR && EXPR { .. }

// After...
if let PAT = ( EXPR && EXPR ) { .. }

// Before...
if let PAT = EXPR || EXPR { .. }

// After...
if let PAT = ( EXPR || EXPR ) { .. }