Rust 学习笔记:高级函数和闭包

【Rust闭包】rust语言闭包函数原理用法汇总与应用实战 闭包(Closure)是 Rust 中一个强大且灵活的特性,它允许你捕获环境中的变量并在稍后执行。Rust 的闭包设计既高效又安全,是函数式编程风格的重要组成部分。 Rust 的 闭包(closures)是可以保存进变量或作为参数传递给其他函数的匿名函数。 可以在一个地方创建闭包,然后在不同的上下文中执行闭包运算。 不同于函数,闭包允许捕获调用者作用域中的值。 阅读详情

Rust 学习笔记:高级函数和闭包

本节探讨与函数和闭包相关的一些高级特性,包括函数指针和返回闭包。

函数指针

我们可以将常规函数传递给函数!当你想传递一个已经定义的函数而不是定义一个新的闭包时,这种技术非常有用。函数强制转换为 fn 类型(带有小写的 f),不要与 Fn 闭包 trait 混淆。fn 类型称为函数指针。传递带有函数指针的函数将允许你将函数用作其他函数的参数,指定参数为函数指针的语法类似于闭包。

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!("{answer}");
}

我们定义了一个函数 add_one,它将参数加 1。函数 do_twice 接受两个形参:一个函数指针指向接受 i32 形参并返回 i32 的任何函数,另一个是一个 i32 值。do_twice 函数调用函数 f 两次,将 arg 值传递给它,然后将两次函数调用结果相加。

这段代码打印 12。

与闭包不同,fn 是一个类型而不是一个 trait,所以我们直接指定 fn 作为参数类型,而不是声明一个泛型类型参数,其中带一个 fn trait 作为 trait 约束。

函数指针实现了所有三个闭包 trait(Fn、FnMut 和 FnOnce),这意味着对于期望闭包的函数,你始终可以将函数指针作为参数传递。

最好使用泛型类型和闭包特征之一来编写函数,这样你的函数就可以接受函数或闭包。

当你与没有闭包的外部代码进行接口时,你希望只接受 fn 而不接受闭包的一个示例是:C 函数可以接受函数作为参数,但 C 没有闭包。

作为可以使用内联定义的闭包或命名函数的示例,让我们看一看标准库中 Iterator trait 提供的 map 方法的用法。要使用 map 方法将数字向量转换为字符串向量,可以使用闭包,如下所示:

    let list_of_numbers = vec![1, 2, 3];
    let list_of_strings: Vec<String> =
        list_of_numbers.iter().map(|i| i.to_string()).collect();

或者我们可以将一个函数命名为 map 的参数,而不是闭包。

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

注意,我们必须使用完全限定语法,因为有多个名为 to_string 的函数可用。这里,我们使用 ToString trait 中定义的 to_string 函数,标准库已经为任何实现 Display 的类型实现了该函数。

每个枚举变量的名称就是一个初始化函数。我们可以将这些初始化函数用作实现闭包 trait 的函数指针,这意味着我们可以将初始化函数指定为接受闭包的方法的参数。

enum Status {
	Value(u32),
	Stop,
}

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

在这里,我们使用使用 Status::Value 的初始化函数调用 map 的范围内的每个 u32 值来创建 Status::Value 实例。

有些人喜欢这种风格,有些人喜欢使用闭包。它们编译成相同的代码,所以使用哪种取决于你。

返回闭包

闭包由 trait 表示,这意味着不能直接返回闭包。

在大多数情况下,你可能希望返回一个 trait,你可以使用实现该 trait 的具体类型作为函数的返回值。但是,闭包通常不能这样做,因为它们没有可返回的具体类型。例如,如果闭包从其作用域捕获任何值,则不允许使用函数指针 fn 作为返回类型。

相反,我们通常使用 impl Trait 语法。你可以使用 Fn、FnOnce 和 FnMut 返回任何函数类型。

fn returns_closure() -> impl Fn(i32) -> i32 {
    |x| x + 1
}

然而,每个闭包也是它自己独特的类型。如果你需要处理具有相同签名但实现不同的多个函数,则需要为它们使用 trait 对象。

考虑一下,如果编写下列代码会发生什么。

fn returns_closure() -> impl Fn(i32) -> i32 {
    |x| x + 1
}

fn returns_initialized_closure(init: i32) -> impl Fn(i32) -> i32 {
    move |x| x + init
}

fn main() {
    let handlers =
    	vec![returns_closure(), returns_initialized_closure(123)];
    for handler in handlers {
        let output = handler(5);
        println!("{output}");
    }
}

这里我们有 returns_closure 和 returns_initialized_closure 两个函数,它们都返回 impl Fn(i32) -> i32。注意,它们返回的闭包是不同的,尽管它们实现了相同的类型。Rust 告诉我们编译错误:

在这里插入图片描述

错误消息告诉我们,每当我们返回一个 impl Trait 时,Rust 就会创建一个唯一的不透明类型,在这个类型中,我们无法看到 Rust 为我们构造的细节。因此,即使这两个函数都返回实现相同 trait(Fn(i32) -> i32)的闭包,Rust 为每个函数生成的不透明类型是不同的。

这类似于 Rust 如何为不同的异步块生成不同的具体类型,即使它们具有相同的输出类型。

这个问题的一种解决方案是使用 trait 对象。

fn returns_closure() -> Box<dyn Fn(i32) -> i32> {
    Box::new(|x| x + 1)
}

fn returns_initialized_closure(init: i32) -> Box<dyn Fn(i32) -> i32> {
    Box::new(move |x| x + init)
}

这样就能通过编译了。

有关 trait 对象的更多信息,请参阅:Rust 学习笔记:trait 对象。

练习题

考虑以两种方式实现一个注册函数,该函数接受一个回调函数。

fn register1(cb: fn(event) -> ());
fn register2(cb: F) where F: Fn(event) -> ();

哪种类型签名允许注册函数接受最广泛的参数类型?

A. register1
B. register2
C. 这两个签名是等价的

答:B。

网络工程系统CAD图:从设计到落地的关键技能与实战指南 网络工程并不只是配置路由器和交换机,真正的核心在于将设计方案转化为可施工的物理图纸。网络工程系统CAD图正是连接逻辑设计与物理世界的桥梁,它涵盖综合布线、信息点布置、桥架路由、弱电间规划等关键内容。理解并掌握这套图纸体系,是网络工程师从基础设备调试走向项目主导者、弱电总工乃至网络架构师的重要分水岭。在园区网、数据中心、智能楼宇等真实场景中,一套规范的系统CAD图直接决定了施工质量、验收效率与后期运维的可靠性。本文从基础概念出发,拆解图纸的组成层次、绘制流程和软件工作流,并结合学习路线与就业方向,帮助初学者建 阅读详情

相关推荐

CentOS 7/8 系统下,基于Docker Compose一键部署Dify AI应用平台

本文详细介绍了在CentOS 7/8系统下,使用Docker Compose一键部署Dify AI应用平台的完整流程。从系统环境准备、Docker引擎安装与加速配置,到获取Dify项目、关键环境变量设置,再到服务启动、状态监控及初始化访问,提供了手把手的部署指南和常见问题排查方法,帮助用户快速搭建稳定、可维护的AI应用开发环境。

q5r6s7的博客 139

rust使用trait实现回调函数对象注册、反注册、回调函数调用

use std::rc::{Rc, Weak}; use std::sync::{Arc}; // 监听事件类型 enum EventType { Click, DoubleClick, Touch, None, } // 监听事件 struct Event { e_type: EventType, } // 处理事件 trait HandleEvent { fn on_event(&self, event: &Event); } /.

u011376563的博客 2409

告别枯燥的Unity编辑器脚本:Odin插件如何让游戏数据配置变得像搭积木一样简单?

本文详细介绍了Odin插件如何简化Unity编辑器脚本开发,使游戏数据配置变得直观高效。通过声明式特性和丰富的可视化工具,Odin让开发者告别繁琐的OnGUI代码,实现所见即所得的开发体验。文章重点展示了Odin的核心优势、魔法特性及实战案例,帮助Unity开发者提升工作效率。

weixin_28717411的博客 345

【Rust】——高级函数与闭包以及宏

目录 🎯函数指针 🎯返回闭包 🎯宏 🎯宏和函数的区别 🎯使用macro_rules!的声明宏用于通用元编程 🎯用于从属性生成代码的过程宏 🎯如何编写自定义derive宏 🎯类属性宏 🎯类函数宏

shsjssnn的博客 5075

运动目标成像必学:5分钟搞懂keystone变换原理与避坑指南

本文深入浅出地解析了雷达信号处理中的Keystone变换原理,它是解决运动目标距离徙动问题的关键技术。文章通过直观比喻和简化公式,阐述了该变换如何通过变量代换实现距离与慢时间的解耦合,将倾斜轨迹“掰直”,从而提升成像与检测性能。同时,文中重点指出了实际应用中关于大速度场景、插值误差、多目标处理及高阶运动补偿等关键避坑点,为工程实践提供了宝贵指南。

ios99的博客 403

MIPI D-PHY TX 一致性测试实例解析 Part 03

本文之前,已经讨论了MIPI D-PHY TX的1.3.x和1.4.x的测试项,1.5.x的测试项相对较少,主要是用于时钟和数据通道相关的时序测量

一只豌豆象的博客 5185

深入探索 Rust 的高级函数与闭包

在 Rust 中,函数和闭包都是“第一类公民”,它们不仅可以作为独立的代码块使用,还可以作为参数传递、返回值输出,甚至参与泛型编程。在这篇博客中,我们将探讨两个高级特性: - **函数指针**:如何将已定义的普通函数作为参数传递给其他函数; - **返回闭包**:如何返回闭包(匿名函数)的同时处理闭包的具体类型问题。

hello.reader 1811

【RT-DETR涨点改进】全网独家-特征融合改进篇 | AAAI 2025 顶会| 高效涨点,RT-DETR利用CDFA对比度特征聚合模块,适用于目标检查(全网独家创新)

本文提出了一种基于CDFA模块的多级特征融合优化RT-DETR模型,用于解决医学图像分割中的软边界模糊、小目标和共现现象等问题。CDFA模块通过对比度特征聚合、局部特征增强和多级注意力机制,有效提升模型性能。研究提供了三种改进方案(rtdetr-r18/y50/l-CDFA),并在多个医学数据集上验证了其有效性。核心创新包括语义信息解耦、对比驱动特征融合和尺寸感知解码器。实验结果表明,该方法在分割精度和鲁棒性方面达到SOTA水平。

Ai缝合怪、助力小伙伴高效发论文 509

Rust 学习笔记:闭包

Rust 学习笔记:闭包

ProgramNovice的博客 1504

WebRTC之beamforming算法

CSND已永久停更,最新版唯一来源点击下面链接跳转: 语音增强和语音识别网页书 坐标问题 这里以笔记本为例进行说明,当笔记本按如下方式打开: 首先是键盘和液晶屏呈90度,然后鼠标上方,也就是液晶屏上方正中间是camera,把平行于键盘的面看成是xy平面,把液晶屏所在的面看成是xz平面,所有平面的原点都在Camera的位置。 方位角:从原点开始,Camera的右侧是0度,逆时针方...

shichaog的专栏 1万+

ChatTutor:让AI老师“会写会画”,打造可视化、互动式智能教育新范式

ChatTutor是一款突破性的开源AI教学助手,通过可视化电子白板实现"边讲边写"的沉浸式教学体验。该项目支持数学公式手写输入、动态函数绘图、自动生成思维导图等功能,采用多智能体架构实现专业协同。未来将扩展至编程、物理等STEM教育领域,适用于学生自学、教师备课和教育平台集成。作为MIT协议开源项目,ChatTutor通过赋予AI"教学肢体语言",推动教育从信息传递转向可视化互动建构,重新定义了AI助教的可能性。

这里汇聚了前沿的技术分享与实用的开发技巧,带你探索从创意到企业的技术创业之路。 423

【Rust自学】19.3. 高级函数和闭包

我们之前讲过如何把闭包传给函数,而实际上我们还可以把函数传递给函数。在传递过程中,函数会被强制转换为`fn`类型,也就是函数指针(function pointer)。

A Rookie in San Domenico School 1346

鸿蒙系统开发工程师:核心技术解析与深度面试指南

摘要: 鸿蒙系统开发工程师需具备底层驱动开发、系统移植优化及分布式架构能力。核心职责包括硬件适配(Bootloader、内核移植、HDF驱动开发)、性能调优(启动加速、功耗管理)及稳定性保障。技术要求涵盖C/C++编程、Linux内核机制、鸿蒙架构(HDF、分布式服务)及ArkTS/ArkUI基础。面试重点考察系统移植流程(如ARM板适配)、驱动开发(I2C/Display)、性能优化手段及内存/同步机制的应用。

郑伟强dev的专栏 429

Rust 高级函数与闭包

对于大部分需要返回 trait 的情况,可以使用实现了期望返回的 trait 的具体类型来替代函数的返回值。作为初始化语法,这看起来就像函数调用,同时它们确实被实现为返回由参数构造的实例的函数。倾向于编写使用泛型和闭包 trait 的函数,这样它就能接受函数或闭包作为参数。而不接受闭包的情况的例子是与不存在闭包的外部代码交互时:C 语言的函数可以接受函数作为参数,但 C 语言没有闭包。作为一个既可以使用内联定义的闭包又可以使用命名函数的例子,让我们看看一个。文件名: src/main.rs。

m0_52796585的博客 911

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Rust学习笔记_12——闭包

在Rust编程语言中,闭包(closures)是一种匿名函数,它能够捕获并存储其所在作用域内的变量,以便在稍后的某个时间点调用。在大多数情况下,你不需要显式地指定闭包的类型,因为Rust的编译器能够推断它。当闭包以移动方式捕获变量时,原始变量将不再可用,因为闭包已经接管了该变量的所有权。不可变捕获是闭包捕获变量的默认方式。当闭包以不可变方式捕获变量时,它只能读取该变量的值,而不能修改它。这种方式保证了闭包内部对变量的访问是安全的,因为闭包不会改变变量的状态。可变捕获允许闭包修改其捕获的变量的值。

LuckyLay的博客 1396

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Rust的闭包

文章目录Rust的闭包创建闭包闭包捕获当前环境中的变量闭包作为函数参数 Rust的闭包 几乎每一种比C语言高级的语言都有闭包。Rust也同样支持闭包。闭包有一个很通俗的名称:匿名函数,它有着如下优点: 创建闭包不用为函数取名,方便快捷 闭包可以捕获调用者作用域中的值 闭包可以被保存进变量或作为参数传递给其他函数 创建闭包 Rust创建闭包的语法很简单:|参数列表| -> 返回类型 {代码段}。用两个竖线将函数参数包裹起来,后面接返回值的类型,最后是用花括号包裹的代码段就可以了。如: fn main

鸿鹄之志 4130

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

【rust中的闭包】

简而言之,闭包就是可以直接访问其外部作用域的函数内部匿名函数(有点狭隘,不过大部分如此)。如果你只想调用一次,用Fnonce,如果你想改变用FnMut,如果你想在多线程中使用且不改变用Fn.“我们都无法确定选择是否正确,只是努力把选择变得正确.”

m0_37719524的博客 1425

Rust编程学习 - 如何学习有关函数和闭包的高级特性,这包括函数指针以及返回闭包

本文介绍了Rust中函数指针和闭包的高级特性。函数指针(fn类型)允许将常规函数作为参数传递,与闭包不同但实现相同的闭包trait。通过示例展示了函数指针的使用场景,如标准库中的map方法。在返回闭包时,需要使用impl Fn语法,但由于每个闭包都有独立类型,处理多个实现相同签名的函数时需使用trait对象。最后提到这些特性为后续实现多线程Web服务器奠定了基础,包括TCP监听、HTTP请求处理、线程池优化等核心功能,展示了Rust在系统编程中的底层控制能力。

2301_79651252的博客 995

【2025 Rust学习 --- 13 闭包:Rust的Lambda】

Rust独特的Lambda

weixin_53800025的博客 2353

【Rust自学】13.1. 闭包 Pt.1:什么是闭包、如何使用闭包

闭包是可以捕获其所在环境的匿名函数。闭包的特点有四:1.闭包是匿名函数 2.这个匿名函数可以保存为变量,或是作为参数传给另一个函数,还可以作为另外一个函数的返回值 3.可以在一个地方创建闭包,然后在另一个上下文中调用闭包来完成运算 4.闭包可以从其定义的作用域内捕获值

A Rookie in San Domenico School 1648

Rust中闭包:Fn、FnOnce和FnMut

闭包的英文是closure,如果你从来没听过着名词,可以这么简单理解,闭包就是一种特殊的,由于可以捕获环境变量,像一个包一样,环境变量捕获,所以称之闭包。以下是两段代码来解释什么是闭包 闭包直观的特点:那么,所谓的捕获环境变量是怎么一回事?让我们看代码 证明一下,普通函数的函数体不能直接使用环境变量 以上例子我们可以看出:在对闭包建立了初步认识之后,我们会想,为什么要设计闭包这种特殊的函数? 以上场景中,如果要做两道面点,那我得写两个,但是步骤一和步骤三其实是一样的,这样就存在代码冗余。有了闭包就可以这样

mikisan555的博客 1907

Rust:闭包作为参数和返回值

闭包作为参数和返回值 闭包作为参数(Taking closures as arguments) 现在我们知道了闭包是trait,我们已经知道了如何接受和返回闭包;就像任何其它的trait! 这也意味着我们也可以选择静态或动态分发。首先,让我们写一个获取可调用结构的函数,调用它,然后返回结果: where F : Fn(i32) -> i32 { ...

chenxuanhanhao的专栏 3019

Rust从入门到精通06-函数和闭包

/ 函数体// 可以包含多条语句和表达式// 可以使用 return 语句返回值fn:函数定义的关键字。:函数的名称,应使用 snake_case 命名规范。:函数的参数列表,每个参数都有名称和类型。ReturnType:函数的返回类型,用于指定函数返回的值的类型。函数体:由大括号{}包围的代码块,包含函数的实际实现。①、Rust 的函数使用关键字 fn 开头,函数名称使用snake case规范风格(所有字母小写并使用下划线分隔);②、可以有一系列的输入参数,可以有一个返回值;

2501_90594826的博客 975

Rust 08:函数和闭包(FnOnce、FnMut、Fn)

Rust是函数式编程语言,函数是一等公民。函数本身可以作为参数进行传递,也可用作函数返回值的类型。 闭包是能够捕获当前上下文中变量的一种特殊结构,能被当做函数一样调用。

编程架构三分天下:分层、分治、分时序。 3107

Rust闭包

闭包

qq_74143285的博客 925

【Rust】 4. 函数与闭包

总结: 闭包提供了比函数更大的灵活性,特别是在需要捕获上下文和进行函数式编程的场景中。在 Rust 中,函数是一等公民(First-class citizens),可以像普通值一样被赋值、传递和返回。特点: 发散表达式可以被转换为任何类型,这在需要统一类型的场合(如 match 表达式的不同分支)很有用。函数体内可以定义其他项(如静态变量、常量、嵌套函数、trait、类型等)。这是闭包与函数最核心的区别:闭包可以捕获并使用其定义作用域内的变量。返回值:函数可以返回一个值,或不返回任何值(即返回 ())。

weixin_43219667的博客 1217
上一篇: Rust 学习笔记:关于高级 trait 的练习题
下一篇: Rust 学习笔记:高级类型
UestcXiye
博客等级 码龄8年 9029粉丝 1306原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UestcXiye

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值