首页 技术杂谈 正文
  • 本文约650字,阅读需3分钟
  • 272
  • 0

Rust - 闭包

摘要

Rust闭包,匿名函数的灵活运用。它们可以捕获并存储环境变量,支持高阶函数特性,是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关键字,可以强制闭包取得它所使用的环境值的所有权
    • 在将闭包传递给新线程以移动数据使其归新线程所有时,此技术最为有用
评论