Rust 函數(shù)式編程的具體使用
Rust 是一門多范式語言,既可以像 C++/Java 那樣寫“命令式代碼”,也支持“函數(shù)式編程”。但很多剛?cè)腴T的小伙伴可能會有這些疑問:
函數(shù)不就是函數(shù)嗎?什么是純函數(shù)?
什么又是副作用?函數(shù)式和我熟悉的 Java/C++ 有啥區(qū)別?
我該怎么開始寫函數(shù)式風(fēng)格的 Rust 代碼?
別急,今天我們從零出發(fā),把這些看起來很抽象的概念通通講清楚!
一、什么是函數(shù)式編程?一句話概括
函數(shù)式編程(Functional Programming)是:用純粹、可組合的函數(shù)來表達(dá)程序邏輯,同時避免副作用。
看不懂?我們來一句一句拆開講 ??
1. 什么是“純粹的函數(shù)”(純函數(shù))?
很多人第一反應(yīng)是:“函數(shù)不都是函數(shù)嗎?為啥還要強(qiáng)調(diào)‘純’?”
來,舉個例子你就懂了:
舉個例子
fn add(a: i32, b: i32) -> i32 {
a + b
}
這個函數(shù):
- 輸入什么,輸出就是什么(比如 2 + 3 永遠(yuǎn)等于 5)
- 不會打印東西、不寫文件、不改全局變量
? 所以它是個“純函數(shù)”。
再舉一個反面例子
fn print_and_add(a: i32, b: i32) -> i32 {
println!("正在加法運算!");
a + b
}
這個函數(shù)除了計算結(jié)果,還打印了一句話,這叫做副作用。
2. 什么是“副作用”?
副作用 = 函數(shù)除了返回結(jié)果,還影響了“外部世界”。
| 行為 | 是副作用嗎? | 原因 |
|---|---|---|
| 改了一個全局變量 | ? 是 | 改變了外部狀態(tài) |
打印輸出 println! | ? 是 | 改變了控制臺 |
| 寫入文件 | ? 是 | 改變了磁盤狀態(tài) |
| 發(fā) HTTP 請求 | ? 是 | 影響了外部網(wǎng)絡(luò) |
| 單純返回值 | ? 否 | 沒動外部任何東西 |
為什么函數(shù)式編程追求“無副作用”?
因為副作用:
- 會讓程序變得難以預(yù)測(打印/寫文件在哪影響了誰?)
- 不利于并發(fā)(多個線程操作全局變量可能會打架)
- 不好測試(一個函數(shù)打印日志、改配置很難自動驗證)
3. 什么是“組合性”?為啥函數(shù)式編程要“可組合”?
組合性 = 把小函數(shù)像積木一樣拼起來,組成更大的邏輯
比如:
let data = vec![1, 2, 3, 4, 5];
let result: i32 = data
.iter() // 遍歷
.filter(|x| *x % 2 == 0) // 只保留偶數(shù)
.map(|x| x * 2) // 每個數(shù)翻倍
.sum(); // 求和
println!("{}", result); // 輸出 12(2*2 + 4*2)
這段代碼沒有循環(huán)、沒有中間變量,卻能一步步地處理數(shù)據(jù)。
每個函數(shù)(如 filter, map)都很簡單,但組合起來就完成了復(fù)雜的邏輯!
這種“拼積木”的能力,就是組合性。
函數(shù)式編程的三大思想總結(jié):
| 概念 | 通俗解釋 | 關(guān)鍵目的 |
|---|---|---|
| 純函數(shù) | 不依賴外部,不改外部,只靠輸入決定輸出 | 穩(wěn)定、可預(yù)測 |
| 無副作用 | 不打印、不改文件、不改全局變量 | 可測試、線程安全 |
| 可組合 | 把小函數(shù)組合成大邏輯 | 簡潔、模塊化 |
函數(shù)式 VS 命令式(C++/Java)
| 對比點 | 命令式(C++/Java) | 函數(shù)式(Rust風(fēng)格) |
|---|---|---|
| 編程方式 | 寫“怎么做” | 寫“要什么” |
| 控制結(jié)構(gòu) | for、if、變量改來改去 | map/filter/鏈?zhǔn)教幚?/td> |
| 狀態(tài)管理 | 變量經(jīng)常變化 | 默認(rèn)不可變 |
| 副作用 | 難避免 | 盡量消除 |
| 函數(shù)角色 | 封裝邏輯 | 構(gòu)建模塊 |
| 可讀性 | 操作細(xì)節(jié)多 | 更像自然語言表達(dá) |
Rust 支持函數(shù)式編程的方式(顯著特征表)
| 特征 | Rust 中的支持方式 | 示例 |
|---|---|---|
| ? 純函數(shù) | 所有普通函數(shù)默認(rèn)都可以寫成純函數(shù) | fn add(a, b) -> a + b |
| ? 不可變性 | 默認(rèn) let 是不可變的 | let x = 5; |
| ? 閉包(匿名函數(shù)) | 使用 |x| x + 1 定義 | let f = |x| x + 1; |
| ? 高階函數(shù) | 函數(shù)可以作為參數(shù)傳入 | map(|x| x * 2) |
| ? 惰性計算 | Iterator 是惰性執(zhí)行的 | .iter().map().filter() |
| ? 函數(shù)組合 | 使用鏈?zhǔn)秸{(diào)用 | .map().filter().sum() |
?? 解釋閉包:閉包就是一個沒有名字的“臨時函數(shù)”,可以捕獲外部變量,語法是 |參數(shù)| 表達(dá)式。
如何從零開始上手 Rust 函數(shù)式編程?
很多人卡在一開始不知道怎么寫函數(shù)式代碼,我們一步步來:
第一步:掌握函數(shù)式寫法格式
| 寫法 | 示例 | 含義 |
|---|---|---|
| 匿名函數(shù)(閉包) | 使用 |x| x + 1 定義 | let f = |x| x + 1; |
| 高階函數(shù) | map(|x| x * 2) | 傳函數(shù)給函數(shù) |
| 鏈?zhǔn)秸{(diào)用 | .filter().map() | 像流水線一樣處理數(shù)據(jù) |
| collect 收集結(jié)果 | .collect::<Vec<_>>() | 把處理結(jié)果收集成 Vec |
第二步:從 for 循環(huán)重構(gòu)開始
傳統(tǒng)寫法:
let mut result = vec![];
for i in 1..=5 {
if i % 2 == 0 {
result.push(i * 2);
}
}
函數(shù)式寫法:
let result: Vec<_> = (1..=5)
.filter(|x| x % 2 == 0)
.map(|x| x * 2)
.collect();
第三步:試著傳函數(shù)給函數(shù)(高階函數(shù))
fn operate(x: i32, f: fn(i32) -> i32) -> i32 {
f(x)
}
fn main() {
let double = |x| x * 2;
println!("{}", operate(3, double)); // 輸出 6
}
總結(jié):Rust 函數(shù)式編程,到底有什么價值?
| 優(yōu)點 | 對初學(xué)者的意義 |
|---|---|
| ? 代碼更短更清晰 | 不需要手動管理中間變量 |
| ? 更容易測試 | 沒副作用就是好測試 |
| ? 更少 bug | 不容易改錯變量 |
| ? 更好并發(fā)支持 | 不爭搶變量,天然線程安全 |
后續(xù)你可以這樣學(xué)習(xí)函數(shù)式思維:
- 把所有
for循環(huán)都試著用.iter().map().filter()改寫 - 學(xué)會閉包、理解閉包和變量捕獲
- 閱讀標(biāo)準(zhǔn)庫
IteratorTrait 的文檔 - 多寫鏈?zhǔn)浇M合:map、filter、fold、collect
- 理解
Option/Result和函數(shù)式結(jié)合的優(yōu)雅用法
到此這篇關(guān)于Rust 函數(shù)式編程的具體使用的文章就介紹到這了,更多相關(guān)Rust 函數(shù)式編程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Rust 中的 Packages 與 Crates模塊化構(gòu)建的基礎(chǔ)及開發(fā)流程
Rust中的Crate是編譯器處理的最小代碼單元,可以是二進(jìn)制或庫,每個Crate由一個CrateRoot文件(通常是src/main.rs或src/lib.rs)定義,本文給大家介紹Rust 中的 Packages 與 Crates模塊化構(gòu)建的基礎(chǔ)及開發(fā)流程,感興趣的朋友一起看看吧2025-02-02
Rust中的Box<T>之堆上的數(shù)據(jù)與遞歸類型詳解
本文介紹了Rust中的Box<T>類型,包括其在堆與棧之間的內(nèi)存分配,性能優(yōu)勢,以及如何利用Box<T>來實現(xiàn)遞歸類型和處理大小未知類型,通過Box<T>,Rust程序員可以更靈活地管理內(nèi)存,避免編譯時大小不確定的問題,并提高代碼的效率和靈活性2025-02-02

