【Rust自学】19.3. 高级函数和闭包 19.3 高级函数和闭包19.3.1 函数指针我们已经讲过把闭包传进函数。实际上我们也可以把函数传进函数。在传递时函数会被强制转换成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!(The answer is: {answer}); }do_twice的第一个参数f的类型是fn也就是函数指针。它期望一个参数类型为i32、返回类型也为i32的函数。函数体中调用了两次f。输出The answer is: 12函数指针与闭包的区别闭包至少实现了Fn、FnOnce和FnMut这三个 trait 之一。函数指针fn是一个类型不是 trait。我们可以直接把fn指定为参数类型而不必声明一个以Fntrait 为约束的泛型参数。函数指针实现了全部三种闭包 trait也就是Fn、FnOnce和FnMut。所以你总是可以把函数指针作为参数传给接受闭包的函数。正因为如此我们编写函数时通常更倾向于使用带闭包 trait 的泛型参数因为这样函数既能接受闭包也能接受普通函数。在某些情况下我们可能想接受fn类型而不是闭包例如与不支持闭包的代码交互时比如 C 函数。该怎么写呢看一个例子fn main() { let list_of_numbers vec![1, 2, 3]; let list_of_strings: VecString list_of_numbers .iter() .map(|i| i.to_string()) .collect(); // 分行只是为了可读性并不是必须的 }list_of_numbers中的元素是i32我们想把它们转换成String赋给list_of_strings。步骤是- 先用iter产生一个迭代器- 再用map中的闭包|i| i.to_string()转换每个元素- 最后用collect把所有转换后的元素收集成一个集合这段代码也可以这样写fn main() { let list_of_numbers vec![1, 2, 3]; let list_of_strings: VecString list_of_numbers .iter() .map(ToString::to_string) .collect(); }区别在于.map(ToString::to_string)这里直接传入了to_string函数。效果与上一版相同。顺便一提ToString::to_string使用了 19.2. 高级 trait关联类型、默认泛型参数和运算符重载、完全限定语法、supertrait 和 newtype 讨论过的完全限定语法。来看一下map的定义fn mapB, F(self, f: F) - MapSelf, F where Self: Sized, F: FnMut(Self::Item) - Bmap要求f实现FnMuttrait而闭包和函数指针都满足这个要求所以两者都可以传入。再看另一个例子fn main() { enum Status { Value(u32), Stop, } let list_of_statuses: VecStatus (0u32..20) .map(Status::Value) .collect(); }注意map的参数。我们使用构造函数Status::Value对范围内的每个u32调用map并创建Status::Value实例。有人可能会问Status::Value不是枚举变体吗怎么变成函数了这是因为在 Rust 中这样的构造函数被实现为接收一个参数并返回新实例的函数。换句话说let v Status::Value(3);这只是一个例子。这里初始化了v而Status::Value(3)可以看作一次构造函数调用3是构造函数的参数。由于构造函数被实现为函数我们可以把它们当作函数来用3就是它们的参数。所以我们也可以把这类构造函数用作实现了闭包 trait 的函数指针。19.3.2 返回闭包闭包通过 trait 来表达因此不能直接从函数返回闭包。相反你可以返回一个实现了该 trait 的具体类型。例如fn returns_closure() - dyn Fn(i32) - i32 { |x| x 1 }这个函数试图直接返回一个闭包。输出error[E0746]: return type cannot be a trait object without pointer indirection -- src/lib.rs:1:25 | 1 | fn returns_closure() - dyn Fn(i32) - i32 { | ^^^^^^^^^^^^^^^^^^ doesnt have a size known at compile-time | help: consider returning an impl Trait instead of a dyn Trait | 1 - fn returns_closure() - dyn Fn(i32) - i32 { 1 fn returns_closure() - impl Fn(i32) - i32 { | help: alternatively, box the return type, and wrap all of the returned values in Box::new | 1 ~ fn returns_closure() - Boxdyn Fn(i32) - i32 { 2 ~ Box::new(|x| x 1) | For more information about this error, try rustc --explain E0746. error: could not compile functions-example (lib) due to 1 previous errorRust 不知道需要多少空间来存储这个闭包所以会报错。还记得我们以前在哪里遇到过同样的“Rust 不知道该分配多少空间”的错误吗没错——在学习链表时。当时的解决办法是用BoxT包裹链表这里也可以这样做fn returns_closure() - Boxdyn Fn(i32) - i32 { Box::new(|x| x 1) }因为返回值位于指针之后返回类型现在在编译时就有了已知大小。

相关新闻

最新新闻

2026硬核实测:4款AI写小说工具怎么选?网文创作全场景深度对比

2026硬核实测:4款AI写小说工具怎么选?网文创作全场景深度对比

当前市面上主打 AI 写小说的工具层出不穷,不同产品的功能侧重、技术路线、适配题材、使用门槛差异很大 —— 有的主打长篇连载连贯性,有的侧重短篇快速量产,有的深耕垂直网文模板,有的主打多模型自由切换,很多作者在选…

2026/7/23 19:35:36
未来十年,智能照明理想图景:商业、工业与豪宅的全光革命

未来十年,智能照明理想图景:商业、工业与豪宅的全光革命

一、商业空间:光成为空间运营的神经末梢1.1 以人为本的办公光环境 理想中的写字楼里,灯具不仅是发光体,更是工位级的“数字副驾”。每个工位上方集成了多光谱传感器和毫米波雷达,实时监测人员存在、姿态甚至眼动特征。系统结合个人…

2026/7/23 19:35:36
TI RTI模块数字窗口看门狗:嵌入式系统时序安全与ISO 26262实践

TI RTI模块数字窗口看门狗:嵌入式系统时序安全与ISO 26262实践

1. 项目概述与核心价值在嵌入式系统,尤其是汽车电子和工业控制这类对可靠性要求极高的领域,系统“跑飞”或陷入死循环是致命的。想象一下,一辆高速行驶的汽车,其发动机控制单元(ECU)的软件因为一个未被捕获…

2026/7/23 19:35:36
React Native鸿蒙跨平台开发:error SyntaxError:Unterminated string constant.解决bug错误

React Native鸿蒙跨平台开发:error SyntaxError:Unterminated string constant.解决bug错误

本文是基于HarmonyOS API 24的进行的ReactNative 鸿蒙跨平台开发依托适配鸿蒙的 RN 运行层,使用 React 与 JS 编写一套业务代码,无需大量 ArkTS 原生开发,通用业务实现代码复用,支持按需扩展原生桥调用鸿蒙特有能力,有…

2026/7/23 19:35:36
硬件CRC控制器:嵌入式系统数据完整性保护的硬件加速方案

硬件CRC控制器:嵌入式系统数据完整性保护的硬件加速方案

1. 项目概述:为什么我们需要硬件CRC控制器? 在嵌入式系统里混久了,你肯定遇到过数据“变脸”的糟心事儿。比如,存储在Flash里的程序代码,运行几个月后某个指令莫名其妙变了;或者通过通信总线收到的传感器数…

2026/7/23 19:35:35
AI生成APP,需求怎么写才少返工

AI生成APP,需求怎么写才少返工

我的结论很明确:用 AI 生成应用时,我把需求写成“角色、对象、状态、规则、验收”五部分,返工会少很多;只写一句功能愿望,页面出得快,后面的逻辑债也来得快。 我这次以产品经理身份做了一个读书会图书漂流…

2026/7/23 19:30:35

月新闻