65_高级函数和闭包

1. 函数指针

在rust中,闭包可以传递给函数,还可以将函数传递给其他函数。在传递的过程中会被强制转换成fn类型,fn类型就是"函数指针"(function pointer)。

如下示例代码:

rust 复制代码
fn add_one(x: i32) -> i32 {
    x + 1
}

fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
    f(arg) + f(arg)
}

fn main() {
    let answer = do_twice(add_one, 5);

    println!("The answer is: {}", answer);
}

2. 函数指针与闭包的不同

闭包实现了三种闭包trait,而函数指针即fn是一个类型,不是一个trait。我们可以直接制定fn为参数类型,不用声明一个以内Fn trait为约束的泛型参数。

函数指针实现了3种闭包trait(Fn, FnMut, FnOnce),所以总是可以把函数指针用作参数传递给一个接收闭包的函数。也正是因为这个原因,我们更倾向于搭配闭包trait的泛型来编写函数,这样这个函数可以同时接收闭包和普通函数作为参数。

某些情景下,我们只想接收fn而不接收闭包,如与外部不支持闭包的代码交互:C函数。我们先看一个示例,将vec的每一个元素转换为String。

如下示例代码:

rust 复制代码
fn main() {
    // 使用闭包
    let list_of_numbers = vec![1, 2, 3];
    let list_of_strings: Vec<String> = list_of_numbers
    .iter()
    .map(|i| i.to_string())
    .collect();

    // 使用函数
    let list_of_numbers = vec![1, 2, 3];
    let list_of_strings: Vec<String> = list_of_numbers
    .iter()
    .map(ToString::to_string)
    .collect();
}

我们再看一个示例,在创建一些枚举数据时,需传入一个数据,并返回一个值。我们可以把这种构造器也作为实现了闭包trait的函数指针来进行使用。

如下示例代码:

rust 复制代码
fn main() {
    enum Status {
        Value(u32),
        Stop,
    }

    let v = Status::Value(2);

    let list_of_statuses: Vec<Status> = 
    (0u32..20)
    .map(Status::Value)
    .collect();
}

3. 返回闭包

闭包使用trait进行表达,无法在函数中直接返回一个闭包,因为rust无法推断出需要多少空间来存储一个返回的闭包,但是可以将一个实现了该trait的具体类型作为返回值。

如下示例代码:

rust 复制代码
fn returns_closure() -> Box<dyn Fn(i32) -> i32> {
    Box::new(|x| x + 1)
}

fn main() {}

4. 总结

  1. Rust中的函数指针是一种类型,表示一个接受特定参数并返回特定结果的函数。
  2. 与闭包不同,函数指针是一个类型,而不是一个trait。
  3. 我们可以将函数指针用作参数传递给一个接收闭包的函数,也可以直接将其作为参数传递给其他函数。
  4. 在某些情况下,我们只想接收fn而不接收闭包,例如与外部不支持闭包的代码交互(如C函数)。
相关推荐
莪_幻尘2 小时前
你的 AI Skill 越多越蠢?Token 上下文爆炸的求生指南
前端·ai编程
lichenyang4532 小时前
从 has.echo 到异步 API 注册表:一次 ASCF API 回调不触发的排查复盘
前端
林瞅瞅3 小时前
Nuxt3 项目部署 Nginx 防盗链后特定 JS 文件 403 问题修复方案
前端
kyriewen3 小时前
别再每次都 Google 了:我整理了前端日常最常踩的 10 个 Git 坑,附速查表
前端·javascript·git
一颗奇趣蛋3 小时前
Web 视频开发完全指南:从入门到精通
前端
非洲农业不发达3 小时前
windows终端体验大升级,让你拥有macos级别的美化
前端·后端
妙码生花4 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(十七):登录接口完善,登录页接口整合,解决跨域
前端·后端·ai编程
唐诗4 小时前
改 3 行配置,我的 Tauri dev 冷启动从 100 秒干到 4 秒
前端·客户端
SmartBoyW4 小时前
深入ECMAScript规范:彻底搞懂JS隐式类型转换与底层ToPrimitive机制
前端·javascript
牧艺4 小时前
Cursor Rules / Skills 分层设计:让 Agent 像「团队新同事」
前端·人工智能·cursor