if 表达式
Syntax
IfExpression →
if Conditions BlockExpressionNoInnerAttributes
( else ( BlockExpressionNoInnerAttributes | IfExpression ) )?
Conditions →
Expressionexcept StructExpression
| LetChain
LetChain → LetChainCondition ( && LetChainCondition )*
LetChainCondition →
Expressionexcept ExcludedConditions
| OuterAttribute* let Pattern = Scrutineeexcept ExcludedConditions
ExcludedConditions →
StructExpression
| LazyBooleanExpression
| RangeExpr
| RangeFromExpr
| RangeInclusiveExpr
| AssignmentExpression
| CompoundAssignmentExpression
if 表达式的语法是由 && 分隔的一个或多个条件操作数的序列,后跟一个结果块,任意数量的 else if 条件和块,以及一个可选的尾部 else 块。
条件操作数必须是一个具有布尔类型的表达式或一个条件 let 匹配。
如果所有条件操作数都求值为 true 且所有 let 模式都成功匹配其受检者,则执行结果块,并跳过任何后续的 else if 或 else 块。
如果任何条件操作数求值为 false 或任何 let 模式未匹配其受检者,则跳过结果块,并求值任何后续的 else if 条件。
如果所有 if 和 else if 条件都求值为 false,则执行 else 块(如果有的话)。
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");
}
// `if` 可以用作表达式。
let y = if 12 * 15 > 150 {
"Bigger"
} else {
"Smaller"
};
assert_eq!(y, "Bigger");
}
如果条件表达式发散或所有分支都发散,则 if 表达式发散。
#![allow(unused)]
fn main() {
fn diverging_condition() -> ! {
// 因为条件表达式发散而发散
if loop {} {
()
} else {
()
};
// 上面的分号很重要:`if` 表达式的类型是 `()`,
// 尽管它发散了。当最终体表达式被省略时,体的类型
// 被推断为 !,因为函数体发散。如果没有分号,
// `if` 将是类型为 `()` 的尾部表达式,这将无法匹配返回类型 `!`。
}
fn diverging_arms() -> ! {
// 因为所有分支都发散而发散
if true {
loop {}
} else {
loop {}
}
}
}
if let 模式
if 条件中的 let 模式允许在模式成功匹配时将新变量绑定到作用域中。
以下示例展示了使用 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!("Irrefutable patterns are always true");
}
}
可以使用 | 运算符指定多个模式。这与 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);
}
}
条件链
多个条件操作数可以用 && 分隔。
类似于 && LazyBooleanExpression,每个操作数从左到右求值,直到某个操作数求值为 false 或 let 匹配失败,在这种情况下后续操作数不会被求值。
每个模式的绑定被放入作用域,以供下一个条件操作数和结果块使用。
以下是链式多个表达式的示例,混合了 let 绑定和布尔表达式,并且表达式可以引用先前表达式的模式绑定:
#![allow(unused)]
fn main() {
fn single() {
let outer_opt = Some(Some(1i32));
if let Some(inner_opt) = outer_opt
&& let Some(number) = inner_opt
&& number == 1
{
println!("Peek a boo");
}
}
}
上面的代码等价于以下不使用条件链的代码:
#![allow(unused)]
fn main() {
fn nested() {
let outer_opt = Some(Some(1i32));
if let Some(inner_opt) = outer_opt {
if let Some(number) = inner_opt {
if number == 1 {
println!("Peek a boo");
}
}
}
}
}
如果任何条件操作数是 let 模式,则由于与 let 受检者的歧义和优先级,所有条件操作数都不能是 || 惰性布尔运算符表达式。如果需要 || 表达式,可以使用括号。例如:
#![allow(unused)]
fn main() {
let foo = Some(123);
let condition1 = true;
let condition2 = false;
// 此处需要括号。
if let Some(x) = foo && (condition1 || condition2) { /*...*/ }
}
2024 Edition differences
在 2024 版本之前,不支持 let 链。即 LetChain 语法在
if表达式中是不允许的。