闭包表达式

语法
闭包表达式 :
   move?
   ( || | | 闭包参数组? | )
   (表达式 | -> 无约束类型组 块表达式)

闭包参数组 :
   闭包参数 (, 闭包参数)* ,?

闭包参数 :
   外围属性* 模式无顶层选项 ( : 类型 )?

闭包表达式 ,也称为 lambda 表达式或 lambda ,定义出 闭包类型 并求值为该类型的值。 闭包表达式的语法 move 关键字可选,随后是管道符号 (|) 包裹的逗号分隔的 模式 列表,称为闭包参数,每个参数后面可选地跟随 : 和类型,然后是可选的 -> 和类型,称为 返回类型 ,随后的表达式,称为 闭包体操作数 。每个模式后面的可选类型是该模式的类型注解。如果存在返回类型,则闭包体必须是

闭包表达式即表示函数,该函数将一系列参数映射到跟随参数的表达式。 和 let 绑定 相同,闭包参数是无法拒绝的 模式 ,其类型注解可选,如果未给出类型,将从上下文中推断。 每个闭包表达式的类型是唯一的、匿名的。

值得注意的是,闭包表达式 捕获其环境 ,而普通的 函数定义 不会。 如果没有 move 关键字,闭包表达式 推断它如何从其环境中捕获每个变量 ,优先通过共享引用来捕获,借用闭包体内用到的所有外部变量。 如果需要,编译器将推断应该取代的是可变引用或者从环境中移动还是复制值 (取决于它们的类型) 。 通过在闭包前面加上 move 关键字,可以强制闭包通过复制或移动值来捕获其环境。 这通常用于确保闭包的生命周期为 'static

闭包类型实现的 trait

闭包类型实现哪些 trait 取决于如何捕获变量和捕获的变量的类型。 请参考 调用 trait 和强转 章节了解闭包实现 FnFnMutFnOnce 的情况和时机。 如果每个捕获的变量的类型也实现了 trait ,则闭包类型实现 SendSync

示例

在这个例子中,我们定义了一个函数 ten_times ,它接受一个高阶函数参数,然后调用该函数,并传入一个闭包表达式作为参数,接着传入一个从环境中移动值的闭包表达式。

#![allow(unused)]
fn main() {
fn ten_times<F>(f: F) where F: Fn(i32) {
    // 遍历 0..10,对每个值调用 f 函数
    for index in 0..10 {
        f(index);
    }
}

// 调用 ten_times 函数,并传入一个匿名函数作为参数,该匿名函数打印出 "hello" 和输入值
ten_times(|j| println!("hello, {}", j));
// 带有类型注解的调用方式,和上一行等价
ten_times(|j: i32| -> () { println!("hello, {}", j) });

let word = "konnichiwa".to_owned();
// 调用 ten_times 函数,并传入一个匿名函数作为参数,该匿名函数打印出 word 和输入值
// 由于匿名函数要使用外部变量 word,所以前面加上 move 关键字
ten_times(move |j| println!("{}, {}", word, j));
}

在闭包参数上的属性

在闭包参数上的属性遵循与 普通函数参数 相同的规则和限制。