闭包表达式
语法
ClosureExpression :
async
1?
move
?
(||
||
ClosureParameters?|
)
(Expression |->
TypeNoBounds BlockExpression)ClosureParameters :
ClosureParam (,
ClosureParam)*,
?ClosureParam :
OuterAttribute* PatternNoTopAlt (:
Type )?1
async
限定符在 2015 edition 中是不允许的。
闭包表达式,也称为 lambda 表达式或 lambda,定义了一个 闭包类型 并求值为该类型的值。闭包表达式的语法是可选的 async
关键字,可选的 move
关键字,然后是由管道符号 (|
) 分隔的逗号分隔的 模式 列表,称为闭包参数,每个参数可以选择后跟 :
和类型,然后是可选的 ->
和类型,称为返回类型,然后是一个表达式,称为闭包体操作数。每个模式后的可选类型是模式的类型注解。如果存在返回类型,则闭包体必须是 block。
闭包表达式表示一个函数,该函数将参数列表映射到跟随参数的表达式。就像 let
绑定 一样,闭包参数是不可反驳的 模式,其类型注解是可选的,如果未给出,则将从上下文中推断。每个闭包表达式都有一个唯一的匿名类型。
重要的是,闭包表达式捕获它们的环境,而常规的 函数定义 则不会。如果没有 move
关键字,闭包表达式 推断它如何从其环境中捕获每个变量,优先通过共享引用捕获,有效地借用闭包体内部提到的所有外部变量。如果需要,编译器将推断应该采用可变引用,或者应该从环境中移动或复制值(取决于它们的类型)。可以通过使用 move
关键字作为前缀来强制闭包通过复制或移动值来捕获其环境。这通常用于确保闭包的生命周期是 'static
。
闭包 trait 的实现
闭包类型实现的 trait 取决于变量的捕获方式、捕获变量的类型以及 async
的存在。有关闭包如何以及何时实现 Fn
、FnMut
和 FnOnce
,请参阅 调用 trait 和强制转换 章节。如果每个捕获变量的类型也实现了该 trait,则闭包类型实现 Send
和 Sync
。
Async 闭包
用 async
关键字标记的闭包表明它们是异步的,类似于 async 函数。
调用 async 闭包不会执行任何工作,而是求值为一个实现了 Future
的值,该值对应于闭包体的计算。
#![allow(unused)] fn main() { async fn takes_async_callback(f: impl AsyncFn(u64)) { f(0).await; f(1).await; } async fn example() { takes_async_callback(async |i| { core::future::ready(i).await; println!("done with {i}."); }).await; } }
Edition 差异:Async 闭包仅从 Rust 2018 开始可用。
示例
在此示例中,我们定义了一个函数 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)); }
闭包参数上的属性
闭包参数上的属性遵循与 常规函数参数 相同的规则和限制。