Rust - 闭包
1.1 什么是闭包
- 闭包:可以捕获其所在环境的匿名函数
- 闭包
- 是一个匿名函数
- 可以保存为变量、或者作为参数传递
- 可在一个地方创建闭包,在另一个上下文中调用闭包来完成运算
- 可从其定义的作用域捕获值
- 闭包的定义方式
多个参数
|param1, param2,...| {
语句1;
语句2;
返回表达式
}
只有一个参数
|param1| 返回表达式
fn main() {
// 定义一个闭包
let x = 10;
let target = |y:i32|{x+1};
println!("{}",target(2));
}
2、练习
// 正常使用函数
use std::thread;
use std::time::Duration;
fn muuu(yd:u32) -> u32{
print!("哈斯~哈斯~\n");
// 停2秒
thread::sleep(Duration::from_secs(2));
yd
}
fn workout(yd:u32,qd:u32){
if yd < 15{
print!("今天活力满满,运动一下,做{}个俯卧撑\n",muuu(yd));
print!("不够,继续,在来{}个卧推\n",muuu(yd));
}else if qd == 3 {
println!("今天强度够了");
}else {
print!("好累,不想练,泡{}分钟澡",muuu(yd));
}
}
fn main() {
// 强度
let intensity = 10;
// 随机值用来决定某个选择
let random_number = 7;
// 开始
workout(intensity, random_number);
}
2.1、通过闭包修改
use std::thread;
use std::time::Duration;
fn workout(yd:u32,qd:u32){
let muu = ||{
print!("哈斯~哈斯~\n");
// 停2秒
thread::sleep(Duration::from_secs(2));
yd
};
if yd < 15{
print!("今天活力满满,运动一下,做{}个俯卧撑\n",muu());
print!("不够,继续,在来{}个卧推\n",muu());
}else if qd == 3 {
println!("今天强度够了");
}else {
print!("好累,不想练,泡{}分钟澡",muu());
}
}
fn main() {
// 强度
let intensity = 10;
// 随机值用来决定某个选择
let random_number = 7;
// 开始
workout(intensity, random_number);
}
3、闭包的类型推倒
- 闭包 : 它可以通过编译器自动推导类型,当编译器推导出一种类型后,它就会一直使用该类型。
fn main(){
let exp = |x|x;
let str_test = exp(String::from("hello"));
// 下面的会报错,因为编译推断不出来类型是什么
let num_test = exp(54);
}
4、结构体中的闭包
- 创建一个struct,它持有闭包及其调用结果
- 只会在需要结果时才执行该闭包
- 可缓存结果
- 这个模式通常叫做记忆化
4.1、如果让Struct持有闭包
- Struct的定义需要知道所有字段的类型
- 需要指明闭包的类型
- 每个闭包实例都有自己唯一的匿名类型,即使两个闭包的签名完全一样
- 为了实现这个约束,需要用到泛型和泛型约束
4.2、Fn Trait
- Fn Trait 由标准库提供
- 所有的闭包都至少实现了以下trait之一:
- fn : 不可变借用
- fn mut : 可变借用
- fn once : 取得所有权
- 创建闭包时,通过闭包对环境值的使用,Rust推断出具体使用哪个trait
- 所有的闭包都实现Fn once
- 没有移动捕获变量的实现了fn mut
- 无需可变访问捕获变量的闭包实现了fn
4.3、代码
// 定义结构体存储数据
struct yundong_shuju<T>
where T : Fn(u32) -> u32{
action:T,
value:Option<u32>
}
// 实现结构体
impl<T> yundong_shuju<T>
where T : Fn(u32) -> u32 {
// 实现构造方法
fn new(action:T) ->yundong_shuju<T> {
yundong_shuju{
action,
value:None,
}
}
// 实现查询方法
fn value(&mut self,arg:u32) ->u32{
match self.value {
Some(v) => v,
None =>{
let v = (self.action)(arg);
v
}
}
}
}
4.4、move关键字
- 在参数列表前使用move关键字,可以强制闭包取得它所使用的环境值的所有权
- 在将闭包传递给新线程以移动数据使其归新线程所有时,此技术最为有用
推荐阅读: