语句
Syntax
Statement →
;
| Item
| LetStatement
| ExpressionStatement
| OuterAttribute* MacroInvocationSemi
语句是块的一个组成部分,而块又是外部表达式或函数的一个组成部分。
声明语句
声明语句是在所包含的语句块中引入一个或多个名称的语句。声明的名称可以表示新的变量或新的项。
声明语句有两种:项声明和 let 语句。
项声明
在语句块中声明一个项会将其作用域限制在包含该语句的块中。该项不会被赋予规范路径,其声明的任何子项也不会。
例外情况是,由实现定义的关联项在外部作用域中仍然可以访问,只要该项以及(如果适用)trait 是可访问的。在其他方面,其含义与在模块中声明该项完全相同。
不会隐式捕获包含该函数的泛型参数、参数和局部变量。例如,inner 不能访问 outer_var。
#![allow(unused)]
fn main() {
fn outer() {
let outer_var = true;
fn inner() { /* outer_var 在此作用域中不可见 */ }
inner();
}
}
let 语句
Syntax
LetStatement →
OuterAttribute* let PatternNoTopAlt ( : Type )?
(
= Expression
| = Expressionexcept LazyBooleanExpression or end with a }
else BlockExpressionNoInnerAttributes
)? ;
let 语句通过模式引入一组新的变量。模式后面可以选择跟上类型标注,然后要么结束,要么跟上一个初始化表达式以及可选的 else 块。
当没有给出类型标注时,编译器会推断类型,或者在没有足够类型信息进行确定推断时报错。
变量声明引入的任何变量从声明点开始可见,直到封闭块作用域结束,除非被另一个变量声明遮蔽。
如果没有 else 块,模式必须是不可反驳的。如果存在 else 块,模式可以是可反驳的。
如果模式不匹配(这要求模式是可反驳的),则执行 else 块。else 块必须总是发散(求值为永不类型)。
#![allow(unused)]
fn main() {
let (mut v, w) = (vec![1, 2, 3], 42); // 绑定可以是 mut 或 const
let Some(t) = v.pop() else { // 可反驳的模式需要 else 块
panic!(); // else 块必须发散
};
let [u, v] = [v[0], v[1]] else { // 此模式是不可反驳的,因此编译器
// 会发出 lint 警告,因为 else 块是多余的。
panic!();
};
}
表达式语句
Syntax
ExpressionStatement →
ExpressionWithoutBlock ;
| ExpressionWithBlock ;?
表达式语句是对表达式求值并忽略其结果的语句。通常,表达式语句的目的是触发对表达式求值产生的效果。
仅由块表达式或控制流表达式组成的表达式,如果在允许语句的上下文中使用,可以省略尾部的分号。这可能导致歧义,因为可能被解析为独立语句或另一个表达式的一部分;在这种情况下,它会被解析为语句。
作为语句使用时,ExpressionWithBlock 表达式的类型必须是单元类型。
#![allow(unused)]
fn main() {
let mut v = vec![1, 2, 3];
v.pop(); // 忽略 pop 返回的元素
if v.is_empty() {
v.push(5);
} else {
v.remove(0);
} // 分号可以省略。
[1]; // 独立的表达式语句,不是索引表达式。
}
当尾部省略分号时,结果必须是类型 ()。
#![allow(unused)]
fn main() {
// bad: 块的类型是 i32,不是 ()
// Error: expected `()` because of default return type
// if true {
// 1
// }
// good: 块的类型是 i32
if true {
1
} else {
2
};
}