闭包表达式

语法

ClosureExpression :

   move?

   ( || | | ClosureParameters? | )

   (Expression | -> TypeNoBounds BlockExpression)

ClosureParameters :

   ClosureParam (, ClosureParam)* ,?

ClosureParam :

   OuterAttribute* PatternNoTopAlt ( : Type )?

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

闭包表达式表示一个函数,该函数将参数列表映射到参数后面的表达式。就像 let 绑定 一样,闭包参数是不可反驳的 模式,其类型标注是可选的,如果没有给出,则将从上下文中推断出来。每个闭包表达式都有一个唯一的匿名类型。

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

闭包特征实现

闭包类型实现哪些特征取决于如何捕获变量以及捕获变量的类型。有关闭包如何以及何时实现 FnFnMutFnOnce,请参阅 调用特征和强制转换 章节。如果每个捕获变量的类型也实现了 SendSync 特征,则闭包类型也实现了 SendSync 特征。

示例

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

#![allow(unused)]
fn main() {
fn ten_times<F>(f: F) where F: Fn(i32) {
    for index in 0..10 {
        f(index);
    }
}

ten_times(|j| println!("hello, {}", j));
// With type annotations
ten_times(|j: i32| -> () { println!("hello, {}", j) });

let word = "konnichiwa".to_owned();
ten_times(move |j| println!("{}, {}", word, j));
}

闭包参数上的属性

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