本教程环境
系统:MacOS
Rust 版本:1.77.2
Rust 的闭包是可以保存在一个变量中或作为参数传递给其他函数的匿名函数。
对一个城市序列进行排序。
struct City {
name: String,
population: i64,
country: String
}
fn sort_cities(cities: &mut Vec<City>) {
cities.sort_by_key(city_population_descending);
}
/// 按照人口数量对城市进行排序的辅助函数
fn city_population_descending(city: &City) -> i64 {
-city.population
}
但是,此时如果将辅助函数写为闭包会更加简洁。
fn sort_cities(cities: &mut Vec<City>) {
cities.sort_by_key(|city| -city.population);
}
捕获变量
闭包可以使用其所在作用域的数据。
/// 根据任何其他的统计标准排序
fn sort_by_statistic(cities: &mut Vec<City>, stat: Statistic) {
cities.sort_by_key(|city| -city.get_statistic(stat));
}
上面的闭包捕获了 stat
。
Rust 没有垃圾回收机制,那么如何保证捕获的变量能够保留以供闭包使用?
- 可以使用借用的方式,此时使用生命周期来保证安全。
- 或使用
move
移动所有权使,将变量的所有权移动到闭包。
函数和闭包的类型
函数的类型
函数和闭包都能当作值使用。意味着它们有自己的类型。
fn city_population_descending(city: &City) -> i64 {
-city.population
}
city_population_descending
函数类型为 fn(&City) -> i64
。
可以对函数执行各种操作。将其存储在变量中。结构体也可以有函数类型的字段。
向量中也可存储函数,只要它们共享同一个 fn
类型。函数还可以作为另一个函数的参数。
闭包类型
但是函数和闭包不是同一种类型。 函数使用的是 fn
类型。闭包需要实现 Fn
特型。
fn(&City) -> bool // fn 类型,只接受函数
Fn(&City) -> bool // Fn 特型,既接受函数也接受闭包
每个闭包都有自己的类型,所有使用闭包的代码通常都应该是泛型的。
Fn trait
闭包捕获和处理环境中的值的方式影响闭包实现的 trait。
Trait 是函数或结构体指定它们能用的闭包的类型的方式。
FnOnce
适用于能被调用一次的闭包,所有闭包都至少实现了这个 trait。FnMut
适用于不会将捕获的值移出闭包体的闭包,但它可修改被捕获的值。这类闭包可被多次调用。Fn
适用于既不将被捕获的值移除闭包体也不修改被捕获的值的闭包,当然也包括不从环境中捕获值的闭包。
闭包性能
在大多数语言中,闭包会在堆中分配内存、进行动态派发以及垃圾回收等。
Rust 闭包则没有这些性能缺陷。它们没有垃圾回收。与 Rust 中的其他类型一样,除非闭包放在 Box、Vec 或其他容器中,否则不会分配到堆上。由于每个闭包都有不同类型,因此 Rust 编译器只要知道你正在调用的闭包类型,就可以内联该闭包的代码。
闭包a使用了两个变量。在内存中,这个闭包像小型结构体,其中包含了对其所用变量的引用。
闭包b使用了 move,会包含值,而非引用。
闭包c不使用任何环境中的变量,该结构体为空,这个闭包不会占用任何内存。
参考链接:
🌟 🙏🙏感谢您的阅读,如果对您有帮助,欢迎关注、点赞 🌟🌟