块表达式
语法
块表达式 :
{
内部属性*
语句组?
}
块表达式 或 块 是控制流表达式和用于条目和变量声明的匿名命名空间作用域。
对于控制流表达式,块按顺序执行其组成的非条目声明语句,然后执行其最后的可选表达式。
在块匿名命名空间作用域内部的条目声明,对于块本身可用,而由 let
语句声明的变量从下一条语句开始到块结束之前可用。
块的语法是 {
,然后是 内部属性 ,以及任意数量的 语句 ,随后是一个可选的表达式,称为最终操作数,和 }
。
语句通常需要在分号后面,有两个例外:
- 条目声明语句不需要在分号后面。
- 表达式语句通常需要分号,除非其外围表达式是控制流表达式。
此外,语句之间允许有额外的分号,但不影响语义。
在评估块表达式时,除条目声明语句外,每个语句都按顺序执行。 然后,如果给定了最终操作数,则执行它。
块的类型是最终操作数的类型,如果省略,则为 ()
。
#![allow(unused)] fn main() { fn fn_call() {} let _: () = { fn_call(); }; let five: i32 = { fn_call(); 5 }; assert_eq!(5, five); }
注意: 对于控制流表达式,如果块表达式是表达式语句的外围表达式,则期望的类型是
()
,除非它紧跟着一个分号。
块始终是值表达式,并在值表达式上下文中计算最终操作数。
注意: 如果确实需要,这一特性可用于强制移动值。例如,以下示例在调用
consume_self
时失败,因为结构体已在块表达式中移动了s
。#![allow(unused)] fn main() { struct Struct; impl Struct { fn consume_self(self) {} fn borrow_self(&self) {} } fn move_by_block_expression() { let s = Struct; // 在块表达式中将值从 `s` 移出。 (&{ s }).borrow_self(); // 无法执行,因为 `s` 已经被移出了。 s.consume_self(); } }
async
块
语法
Async块表达式 :
async
move
? 块表达式
异步块是块表达式的一种变体,值求解为一个 future 。 块的最终表达式 (如果存在) 确定 future 的结果值。
执行异步块类似于执行闭包表达式:
它的即时效果是生成并返回一个匿名类型。
返回实现一个或多个 std::ops::Fn
trait 的类型,异步块返回的类型实现了 std::future::Future
trait。
这种类型的实际数据格式是未指明的。
注意: rustc 生成的 future 类型大致相当于具有每个
await
点一个变体的枚举类型,其中每个变体存储从其相应点恢复所需的数据。 版本差异: 异步块仅在 Rust 2018 及以后版本中可用。
捕获模式
异步块使用与闭包相同的 捕获模式 从环境中捕获变量。
与闭包一样,当写成 async { .. }
时,每个变量的捕获模式将从块的内容推断。
然而, async move { .. }
块将移动所有被引用的变量到生成的 future 中。
异步上下文
由于异步块构造了一个 future ,其定义了一个 异步上下文 ,这个上下文可以包含 await
表达式 。
异步上下文由异步块以及异步函数的函数体构建,异步函数的语义是以异步块为基础进行定义的。
控制流运算符
异步块有类似于函数的约束,就像闭包一样。
因此, ?
运算符和 return
表达式都会影响 future 的输出,而不是封闭函数或其他上下文。
也就是说,从异步块中的 return <expr>
将返回 <expr>
的结果作为 future 的输出。
同样,如果 <expr>?
传播错误,则该错误将作为 future 的结果传播。
最后, break
和 continue
关键字不能用于从异步块中分支跳出。
以下代码是非法的:
#![allow(unused)] fn main() { loop { async move { break; // error[E0267]: `break` inside of an `async` block } } }
unsafe
块
语法
Unsafe块表达式 :
unsafe
块表达式
在需要进行 unsafe 操作 时,可在块之前添加 unsafe
关键字。详见 unsafe
块 。
示例:
#![allow(unused)] fn main() { unsafe { let b = [13u8, 17u8]; let a = &b[0] as *const u8; assert_eq!(*a, 13); assert_eq!(*a.offset(1), 17); } unsafe fn an_unsafe_fn() -> i32 { 10 } let a = unsafe { an_unsafe_fn() }; }
块表达式标签
在 循环和其他可中断表达式 部分进行了说明。
块表达式上的属性
在以下情况下,可以在块表达式的左括号之后直接使用 内部属性 :
- 函数 和 方法 体。
- 循环体 (
loop
、while
、while let
和for
)。 - 作为 语句 使用的块表达式。
- 块表达式作为 数组表达式 、 元组表达式 、 调用表达式 和类似元组的 结构体 表达式的元素。
- 另一个块表达式的尾表达式是块表达式。
在块表达式上具有含义的外围属性包括 cfg
和 代码分析检查属性 。
例如,以下函数在 Unix 平台上返回 true
,在其他平台上返回 false
。
#![allow(unused)] fn main() { fn is_unix_platform() -> bool { #[cfg(unix)] { true } #[cfg(not(unix))] { false } } }