09-闭包
1.3.4 闭包
Rust也支持闭包。闭包与函数类似,但具有声明它们的环境或作用域的更多信息。虽然函数具有与之关联的名称,闭包的定义没有,但可以将它们分配给变量。Rust类型推断的另一个优点是,在大多数情况下,你可以为没有类型的闭包指定参数。这是一个最简单的闭包“let my_closure = || ();”。我们刚刚定义了一个什么都不做的无参数闭包。然后我们可以通过my_closure()来调用它,这和函数类似。两个竖条“||”用于存放闭包的参数(如果有的话),例如|a,b|。当Rust无法找出正确的类型时,有时需要指定参数类型(|a:u32|)。和函数类似,闭包也可以存储在变量中,稍后调用或传递给其他函数。但是,闭包的主体可以是单一表达式,也可以是由花括号标识的多个表达式组成。更复杂的闭包示例如下所示:
// closures.rs
fn main() {
let doubler = |x| x * 2;
let value = 5;
let twice = doubler(value);
println!("{} doubled is {}", value, twice);
let big_closure = |b, c| {
let z = b + c;
z * twice
};
let some_number = big_closure(1, 2);
println!("Result from closure: {}", some_number);
}
在上述代码中,我们定义了两个闭包:doubler和big_closure。doubler将给定的值加倍。在这种情况下,它从父作用域或上下文环境传递value,即main函数。同样,在big_closure中,我们从其环境中使用变量twice。这个闭包在花括号内有多行表达式,需要以分号结尾,以便我们将它分配给变量big_closure。之后,我们调用big_closure,传入1、2作为参数,并输出some_number。
闭包主要用作高阶函数的参数。高阶函数是一个以另一个函数或闭包作为参数的函数。例如,标准库中的thread::spawn函数接收一个闭包作为参数,你可以在其中编写要在另一个线程中运行的代码。闭包提供简便、抽象的另一个场景是,当你有一个对Vec等集合进行操作的函数时,希望根据某些条件过滤元素。Rust的迭代器特征(iterator trait)有一个名为filter的方法,可以接收一个闭包作为参数。此闭包由用户定义,并返回true或false,具体取决于用户希望过滤集合中元素的方式。我们将在第7章深入了解闭包。