Rust中函数作为参数:传递函数的3种方法

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

Rust中函数作为参数:从新手到专家

\n\n

您是否曾经用Python或JavaScript编写代码,轻松地将函数传递给另一个函数?然后转向Rust,却在简单的地方卡住了?很熟悉吧。"How do you pass a Rust function as a parameter?"这个问题是Stack Overflow上最热门的问题之一。这并非没有原因:Rust的类型系统和所有权机制增加了几个层次的复杂性,但也开辟了新的可能性。

\n\n

在本文中,我们将探讨三种主要方法:函数指针(fn)、闭包(closures)和trait。您将了解何时使用哪种方法,并不再畏惧Rust中的函数式风格。

\n\n

为什么这很重要?

\n

能够将函数作为参数传递不仅仅是一个学术技巧。它是以下内容的基础:

\n
    \n
  • 创建灵活且可重用的库(例如,迭代器、事件处理器);
  • \n
  • 实现"策略"和"观察者"模式;
  • \n
  • 编写简洁且富有表现力的代码,避免大量if-else语句。
  • \n
\n

与动态语言不同,在Rust中,编译器会严格检查类型和生命周期。因此,您需要清楚地理解您传递的是什么:仅仅是函数地址、捕获了上下文的闭包,还是更复杂的东西。

\n\n

方法1:函数指针(Function Pointer)—— fn

\n

最简单直接的方法。如果您的函数不捕获外部环境中的变量(它是"纯"函数),可以使用fn类型。请注意:fn是一个类型,而Fn、FnMut、FnOnce是trait。不要混淆!

\n\n
fn add_one(x: i32) -> i32 {\n    x + 1\n}\n\n// 接受另一个函数的函数\nfn apply_twice(f: fn(i32) -> i32, value: i32) -> i32 {\n    f(f(value))\n}\n\nfn main() {\n    let result = apply_twice(add_one, 5);\n    println!("结果: {}", result); // 7\n}
\n\n

何时使用?当函数在编译时已知、不捕获变量且您不需要闭包的性能时。函数指针是零成本抽象,不需要内存分配。

\n\n

fn的局限性

\n

主要缺点:您不能传递捕获变量的闭包。以下代码无法编译:

\n\n
fn main() {\n    let y = 10;\n    // 闭包捕获了y\n    let closure = |x: i32| -> i32 { x + y };\n    // 错误!期望fn项,但找到了闭包\n    // let result = apply_twice(closure, 5);\n}
\n\n

为此,您需要Fn、FnMut、FnOnce这些trait。

\n\n

方法2:闭包和Fn、FnMut、FnOnce trait

\n

Rust是一种系统级语言,它必须了解内存的情况。闭包可以通过三种方式捕获变量:

\n
    \n
  • 通过引用(&T)—— Fn trait。可以任意多次调用,不改变捕获的数据。
  • \n
  • 通过可变引用(&mut T)—— FnMut trait。可以多次调用,但数据可能会改变。
  • \n
  • 通过值(T)—— FnOnce trait。只能调用一次,之后闭包被"消耗"。
  • \n
\n\n

Fn示例

\n
fn apply_twice_fn<F>(f: F, value: i32) -> i32\nwhere\n    F: Fn(i32) -> i32,\n{\n    f(f(value))\n}\n\nfn main() {\n    let y = 10;\n    let closure = |x| x + y; // 通过引用捕获y\n    let result = apply_twice_fn(closure, 5);\n    println!("Fn: {}", result); // 25\n}
\n\n

FnMut示例

\n
fn apply_twice_mut<F>(mut f: F, value: i32) -> i32\nwhere\n    F: FnMut(i32) -> i32,\n{\n    f(f(value))\n}\n\nfn main() {\n    let mut counter = 0;\n    let mut closure = |x: i32| -> i32 {\n                

博客

书籍推荐