Rust中与闭包相关的三个trait
在 Rust 中,闭包就是一种能捕获 上下文环境变量 的函数。
let range = 0..10; let get_range_count = || range.count(); 代码里的这个 get_range_count 就是闭包,range 是被这个闭包捕获的环境变量。
虽然说它是一种函数,但是不通过 fn 进行定义。在 Rust 中,并不把这个闭包的类型处理成 fn 这种函数指针类型,而是有单独的类型定义。
切记这里是将闭包处理成是 单独的类型定义,这一点区别与其它开发语言。
至于按哪一种类型来处理,这个没有办法得知,因为只有在Rust编译器在编译的时候才可以确定其类型,并且在确定类型时,还需要根据这个闭包捕获上下文环境变量时的行为来确定。
闭包trait分类 根据闭包行为划分为三类trait( 主因是受到所有权影响):
FnOnce 适用于能被调用一次的闭包,所有闭包都至少实现了这个 trait,因为所有闭包都必须能够被调用。一个会将捕获的值移出闭包体的闭包只实现 FnOnce trait,这是因为它只能被调用一次。其获取了上下文环境变量的所有权。 FnMut 适用于不会将捕获的值移出闭包体的闭包,但它可能会修改被捕获的值,这类闭包可以被调用多次。其只获取了上下文环境变量的 &mut 引用。 Fn 适用于既不将被捕获的值移出闭包体也不修改被捕获的值的闭包,当然也包括不从环境中捕获值的闭包。这类闭包可以被调用多次而不改变它们的环境,这在会 多次并发调用闭包的场景中十分重要。其只获取了上下文环境变量的 & 不可变引用。 在编译时会将闭包确定为以上三种类型中的一种或多种组合。 Rust 给我们暴露了 FnOnce、FnMut、Fn 这 3 个 trait,就刚对应上面这三类数据类型。
它们在标准库中的定义为
trait FnOnce<Args> { type Output; fn call_once(self, args: Args) -> Self::Output; } trait FnMut<Args>: FnOnce<Args> { fn call_mut(&mut self, args: Args) -> Self::Output; } trait Fn<Args>: FnMut<Args> { fn call(&self, args: Args) -> Self::Output; } 注意这三者的关系,其中 Fn 继承了 FnMut ,而 FnMut 又继承了 FnOnce,它们三者有层次关系的。
read more