Rust Closure 闭包解析(匿名函数)

Rust Closure 闭包解析(匿名函数)

正文

闭包与匿名函数是现代语言对与函数式编程范式常见的实现,与 JavaScript 惊人的相似的是对于外部上下文的变量捕捉等特性,下面我们就来介绍如何在 Rust 中使用闭包,同时它也将作为 Rust 多线程编程中的重要基础知识之一

1. 简单闭包 - 纯粹的匿名函数

首先我们先介绍第一种,最简单的闭包用法,在代码行中创建一个行内匿名函数

  • /src/anonymous_function.rs

基本的函数的类型是 Fn,我们创建一个结构体用于保存一个函数与其运行

extern crate rand;

use std::thread;
use std::time::Duration;
use std::ops::Fn;
use rand::random;

struct FnCache<T> where T: Fn(u32) -> u32 {
    calculation: T,
    value: Option<u32>,
}

然后定义创建构造函数与数据访问函数

impl<T> FnCache<T> where T: Fn(u32) -> u32 {
    fn new(calculation: T) -> FnCache<T> {
        FnCache {
            calculation,
            value: None,
        }
    }

    fn value(&mut self, arg: u32) -> u32 {
        match self.value {
            Some(value) => value,
            None => {
                let value = (self.calculation)(arg);
                self.value = Some(value);
                value
            }
        }
    }
}

接下来我们就能够在行内调用构造函数并传入匿名函数作为可配置的算法过程

fn generate_task(intensity: u32) -> bool {
    let mut expensive_closure = FnCache::new(|num| {
        println!("calculating slowly...");
        thread::sleep(Duration::from_secs(2));
        println!("done!");
        num
    });

    if intensity < 20 {
        println!("intensity = {}, keep working", expensive_closure.value(intensity));
        false
    } else {
        println!("intensity = {}, enough", intensity);
        true
    }
}

我们可以看到 Rust 使用 |params| { statements } 的语法结构来表示匿名函数

最后我们做一个小循环进行测试

pub fn test() {
    println!(">>>>> anonymous_function");

    let mut count = 1;
    loop {
        let i: u32 = random();
        let random_intensity = i % 30;
        let done = generate_task(random_intensity);
        if done || count >= 3 {
            break;
        }
        count += 1;
    }
  • 输出
>>>>> anonymous_function
calculating slowly...
done!
intensity = 7, keep working
intensity = 20, enough

当然实际上我们使用 fn 关键字定义的一般函数实际上也拥有一样的类型签名

fn simple_fn(x: u32) -> u32 {
    println!("simple_fn({})", x);
    x
}

pub fn test() {
    println!("\n! test normal function as Fn");
    let mut cache = FnCache::new(simple_fn);
    println!("cache.value(1) = {}", cache.value(1));
    println!("cache.value(2) = {}", cache.value(2));

    println!();
}
  • 输出
! test normal function as Fn
simple_fn(1)
cache.value(1) = 1
cache.value(2) = 1

2. 捕获上下文 & FnOnce、FnMut、Fn 类型验证

然而闭包最强大的部分除了可以自由在运行时创建函数之外,就是能够捕获上下文环境的变量这个特性,就能够将一些已经消失的作用域中的变量透过闭包捕获并私有化

下面我们使用三个例子来演示使用闭包捕获上下文变量,同时顺便验证 FnOnce、FnMut、Fn 这三个类型的不同之处

  • /src/capture_environment.rs

第一个例子创建一个比较函数,并能够提前绑定参数

fn capture_var(x: u32) -> Box<dyn Fn(u32) -> bool> {
    Box::new(move |y: u32| y == x)
}

pub fn test() {
    println!(">>>>> capture_environment");

    println!("! Fn test");
    let equal_one = capture_var(1);
    println!("equal_one(3) = {}", (*equal_one)(3));
    println!("equal_one(2) = {}", (*equal_one)(2));
    println!("equal_one(1) = {}", (*equal_one)(1));
}
  • 输出
>>>>> capture_environment
! Fn test
equal_one(3) = false
equal_one(2) = false
equal_one(1) = true

第二个例子演示了一个计数器的实现,修改了上下文的变量因此用到了 FnMut 类型

fn counter() -> Box<dyn FnMut(bool) -> u32> {
    let mut val = 0;
    Box::new(move |incr| {
        if incr {
            val += 1;
        }
        val
    })
}

pub fn test() {
    println!("! FnMut test");
    let mut increment = counter();
    println!("increment() = {}", (*increment)(true));
    println!("increment() = {}", (*increment)(true));
    println!("increment() = {}", (*increment)(false));
}
  • 输出
! FnMut test
increment() = 1
increment() = 2
increment() = 2

第三个例子则是测试只能调用一次的函数签名 FnOnce

fn once<T>(f: T) -> Box<dyn Fn() -> u32> where T: FnOnce() -> u32 {
    let val = f();
    Box::new(move || val)
}

pub fn test() {
    println!("! FnOnce test");
    let gettter = once(|| {
        3
    });
    println!("get = {}", (*gettter)());
}
  • 输出
! FnOnce test
get = 3

其他资源

参考连接

TitleLink
Closures: Anonymous Functions that Can Capture Their Environment - The Rust Programming Languagehttps://doc.rust-lang.org/book/ch13-01-closures.html

完整代码示例

https://github.com/superfreeeee/Blog-code/tree/main/back_end/rust/rust_closure

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值