块表达式

语法
块表达式 :
   {
      内部属性*
      语句组?
   }

语句组 :
      语句+
   | 语句+ 无块表达式
   | 无块表达式

块表达式 是控制流表达式和用于条目和变量声明的匿名命名空间作用域。 对于控制流表达式,块按顺序执行其组成的非条目声明语句,然后执行其最后的可选表达式。 在块匿名命名空间作用域内部的条目声明,对于块本身可用,而由 let 语句声明的变量从下一条语句开始到块结束之前可用。

块的语法是 { ,然后是 内部属性 ,以及任意数量的 语句 ,随后是一个可选的表达式,称为最终操作数,和 }

语句通常需要在分号后面,有两个例外:

  1. 条目声明语句不需要在分号后面。
  2. 表达式语句通常需要分号,除非其外围表达式是控制流表达式。

此外,语句之间允许有额外的分号,但不影响语义。

在评估块表达式时,除条目声明语句外,每个语句都按顺序执行。 然后,如果给定了最终操作数,则执行它。

块的类型是最终操作数的类型,如果省略,则为 ()

#![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 的结果传播。

最后, breakcontinue 关键字不能用于从异步块中分支跳出。 以下代码是非法的:

#![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() };
}

块表达式标签

循环和其他可中断表达式 部分进行了说明。

块表达式上的属性

在以下情况下,可以在块表达式的左括号之后直接使用 内部属性 :

在块表达式上具有含义的外围属性包括 cfg代码分析检查属性

例如,以下函数在 Unix 平台上返回 true ,在其他平台上返回 false

#![allow(unused)]
fn main() {
fn is_unix_platform() -> bool {
    #[cfg(unix)] { true }
    #[cfg(not(unix))] { false }
}
}