Rust 函数式编程的具体使用
作者:pumpkin84514
本文主要介绍了Rust 函数式编程的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
Rust 是一门多范式语言,既可以像 C++/Java 那样写“命令式代码”,也支持“函数式编程”。但很多刚入门的小伙伴可能会有这些疑问:
函数不就是函数吗?什么是纯函数?
什么又是副作用?函数式和我熟悉的 Java/C++ 有啥区别?
我该怎么开始写函数式风格的 Rust 代码?
别急,今天我们从零出发,把这些看起来很抽象的概念通通讲清楚!
一、什么是函数式编程?一句话概括
函数式编程(Functional Programming)是:用纯粹、可组合的函数来表达程序逻辑,同时避免副作用。
看不懂?我们来一句一句拆开讲 👇
1. 什么是“纯粹的函数”(纯函数)?
很多人第一反应是:“函数不都是函数吗?为啥还要强调‘纯’?”
来,举个例子你就懂了:
举个例子
fn add(a: i32, b: i32) -> i32 { a + b }
这个函数:
- 输入什么,输出就是什么(比如 2 + 3 永远等于 5)
- 不会打印东西、不写文件、不改全局变量
✅ 所以它是个“纯函数”。
再举一个反面例子
fn print_and_add(a: i32, b: i32) -> i32 { println!("正在加法运算!"); a + b }
这个函数除了计算结果,还打印了一句话,这叫做副作用。
2. 什么是“副作用”?
副作用 = 函数除了返回结果,还影响了“外部世界”。
行为 | 是副作用吗? | 原因 |
---|---|---|
改了一个全局变量 | ✅ 是 | 改变了外部状态 |
打印输出 println! | ✅ 是 | 改变了控制台 |
写入文件 | ✅ 是 | 改变了磁盘状态 |
发 HTTP 请求 | ✅ 是 | 影响了外部网络 |
单纯返回值 | ❌ 否 | 没动外部任何东西 |
为什么函数式编程追求“无副作用”?
因为副作用:
- 会让程序变得难以预测(打印/写文件在哪影响了谁?)
- 不利于并发(多个线程操作全局变量可能会打架)
- 不好测试(一个函数打印日志、改配置很难自动验证)
3. 什么是“组合性”?为啥函数式编程要“可组合”?
组合性 = 把小函数像积木一样拼起来,组成更大的逻辑
比如:
let data = vec![1, 2, 3, 4, 5]; let result: i32 = data .iter() // 遍历 .filter(|x| *x % 2 == 0) // 只保留偶数 .map(|x| x * 2) // 每个数翻倍 .sum(); // 求和 println!("{}", result); // 输出 12(2*2 + 4*2)
这段代码没有循环、没有中间变量,却能一步步地处理数据。
每个函数(如 filter
, map
)都很简单,但组合起来就完成了复杂的逻辑!
这种“拼积木”的能力,就是组合性。
函数式编程的三大思想总结:
概念 | 通俗解释 | 关键目的 |
---|---|---|
纯函数 | 不依赖外部,不改外部,只靠输入决定输出 | 稳定、可预测 |
无副作用 | 不打印、不改文件、不改全局变量 | 可测试、线程安全 |
可组合 | 把小函数组合成大逻辑 | 简洁、模块化 |
函数式 VS 命令式(C++/Java)
对比点 | 命令式(C++/Java) | 函数式(Rust风格) |
---|---|---|
编程方式 | 写“怎么做” | 写“要什么” |
控制结构 | for、if、变量改来改去 | map/filter/链式处理 |
状态管理 | 变量经常变化 | 默认不可变 |
副作用 | 难避免 | 尽量消除 |
函数角色 | 封装逻辑 | 构建模块 |
可读性 | 操作细节多 | 更像自然语言表达 |
Rust 支持函数式编程的方式(显著特征表)
特征 | Rust 中的支持方式 | 示例 |
---|---|---|
✅ 纯函数 | 所有普通函数默认都可以写成纯函数 | fn add(a, b) -> a + b |
✅ 不可变性 | 默认 let 是不可变的 | let x = 5; |
✅ 闭包(匿名函数) | 使用 |x| x + 1 定义 | let f = |x| x + 1; |
✅ 高阶函数 | 函数可以作为参数传入 | map(|x| x * 2) |
✅ 惰性计算 | Iterator 是惰性执行的 | .iter().map().filter() |
✅ 函数组合 | 使用链式调用 | .map().filter().sum() |
🔍 解释闭包:闭包就是一个没有名字的“临时函数”,可以捕获外部变量,语法是 |参数| 表达式
。
如何从零开始上手 Rust 函数式编程?
很多人卡在一开始不知道怎么写函数式代码,我们一步步来:
第一步:掌握函数式写法格式
写法 | 示例 | 含义 |
---|---|---|
匿名函数(闭包) | 使用 |x| x + 1 定义 | let f = |x| x + 1; |
高阶函数 | map(|x| x * 2) | 传函数给函数 |
链式调用 | .filter().map() | 像流水线一样处理数据 |
collect 收集结果 | .collect::<Vec<_>>() | 把处理结果收集成 Vec |
第二步:从 for 循环重构开始
传统写法:
let mut result = vec![]; for i in 1..=5 { if i % 2 == 0 { result.push(i * 2); } }
函数式写法:
let result: Vec<_> = (1..=5) .filter(|x| x % 2 == 0) .map(|x| x * 2) .collect();
第三步:试着传函数给函数(高阶函数)
fn operate(x: i32, f: fn(i32) -> i32) -> i32 { f(x) } fn main() { let double = |x| x * 2; println!("{}", operate(3, double)); // 输出 6 }
总结:Rust 函数式编程,到底有什么价值?
优点 | 对初学者的意义 |
---|---|
✅ 代码更短更清晰 | 不需要手动管理中间变量 |
✅ 更容易测试 | 没副作用就是好测试 |
✅ 更少 bug | 不容易改错变量 |
✅ 更好并发支持 | 不争抢变量,天然线程安全 |
后续你可以这样学习函数式思维:
- 把所有
for
循环都试着用.iter().map().filter()
改写 - 学会闭包、理解闭包和变量捕获
- 阅读标准库
Iterator
Trait 的文档 - 多写链式组合:map、filter、fold、collect
- 理解
Option
/Result
和函数式结合的优雅用法
到此这篇关于Rust 函数式编程的具体使用的文章就介绍到这了,更多相关Rust 函数式编程内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!