rust 自定義迭代器的實(shí)現(xiàn)方法
1. 什么是迭代器???
簡單來說,迭代器就是一個(gè)“知道如何獲取下一個(gè)元素”的東西。
它是一種設(shè)計(jì)模式,允許你遍歷一個(gè)序列(比如數(shù)組、列表或你自定義的任何東西),而不需要關(guān)心序列內(nèi)部是怎么存儲(chǔ)的。
在 Rust 中,你最常見的迭代器用法就是 for 循環(huán):r` 循環(huán):
let numbers = vec![1, 2, 3];
// 這里的 `numbers.iter()` 就創(chuàng)建了一個(gè)迭代器
for num in numbers.iter() {
println!("Got: {}", num);
}
for 循環(huán)就是不斷地問這個(gè)迭代器:“嘿,還有下一個(gè)嗎?有的話請(qǐng)給我。” 直到迭代器回答:“抱歉,沒有了。”
我們的目標(biāo)就是學(xué)會(huì)如何創(chuàng)造這種“東西”。
2. 核心揭秘:IteratorTrait
在 Rust 中,“迭代器”并不是一個(gè)具體的類型,而是**任何了 Iterator Trait 的類型**。
這個(gè) Trait (特質(zhì)) 的定義簡化后是這樣的:
pub trait Iterator {
// 1. 關(guān)聯(lián)類型:告訴 Rust 你迭代的“東西”是什么類型
type Item;
// 2. 核心方法:獲取下一個(gè)元素
// 這是你唯一必須實(shí)現(xiàn)的方法!
fn next(&mut self) -> Option<Self::Item>;
// --- 下面還有很多其他方法 (map, filter, sum...) ---
// 但它們都有默認(rèn)實(shí)現(xiàn),你暫時(shí)不用管!
}
是不是看起來很簡單?我們來拆解一下你必須關(guān)心的兩個(gè)部分:
type Item;
這是一個(gè)關(guān)聯(lián)類型。你只需要告訴 Rust:“我這個(gè)迭代器,每次‘吐’出來的元素是 i32 類型”或者“是 String 類型”。
例如:type Item = u32; 或 type Item = &String;
fn next(&mut self) -> Option<Self::Item>
這就是魔法發(fā)生的地方!??
&mut self:為什么是 &mut (可變借用)?因?yàn)榈餍枰?*狀態(tài)**。比如,一個(gè)計(jì)數(shù)器需要知道“我當(dāng)前數(shù)到幾了”,每次調(diào)用 next 之后,這個(gè)狀態(tài)就要改變(比如 +1)。
Option<Self::Item>:這是迭代器設(shè)計(jì)的精髓!
- **`Some(ue)**:如果序列中還有下一個(gè)元素,就返回 Some(那個(gè)元素)`。
- None:如果序列已經(jīng)結(jié)束了,就返回 None。for 循環(huán)看到 None 就會(huì)自動(dòng)停止。
3. 實(shí)踐一:你的第一個(gè)迭代器 (簡單的計(jì)數(shù)器) ??
我們來寫一個(gè)最簡單的迭代器:一個(gè)從 1 數(shù)到 5 的計(jì)數(shù)器。
第 1 步:定義結(jié)構(gòu)體 (保存狀態(tài))
迭代器需要“記憶”,所以我們需要一個(gè)結(jié)構(gòu)體來保存它的“狀態(tài)”。對(duì)于計(jì)數(shù)器,我們需要知道“當(dāng)前數(shù)到幾了” (current) 和“什么時(shí)候停” (max)。
// 我們的計(jì)數(shù)器結(jié)構(gòu)體
struct Counter {
current: u32,
max: u32,
}
// 順便給它一個(gè) "構(gòu)造函數(shù)" (new)
impl Counter {
fn new(max: u32) -> Counter {
Counter { current: 1, max } // 我們從 1 開始數(shù)
}
}
第 2 步:實(shí)現(xiàn)IteratorTrait
現(xiàn)在,我們來告訴 Rust 如何讓 Counter 變成一個(gè)迭代器。
impl Iterator for Counter {
// 1. 告訴 Rust 我們迭代的是 u32
type Item = u32;
// 2. 實(shí)現(xiàn)核心邏輯!
fn next(&mut self) -> Option<Self::Item> {
if self.current <= self.max {
// 只要當(dāng)前值 <= 5
// 準(zhǔn)備好要返回的當(dāng)前值
let val_to_return = self.current;
// 更新狀態(tài):讓 current + 1,為下一次做準(zhǔn)備
self.current += 1;
// 把值用 Some() 包裹起來返回
Some(val_to_return)
} else {
// 如果 current 已經(jīng) > max (比如到了 6)
// 迭代結(jié)束!返回 None
None
}
}
}
第 3 步:使用它!
恭喜你!你已經(jīng)寫好了一個(gè)完整的迭代器!?? 讓我們用用看:
fn main() {
let counter = Counter::new(5); // 創(chuàng)建一個(gè) 1 到 5 的計(jì)數(shù)器
// `for` 循環(huán)現(xiàn)在可以識(shí)別我們的 Counter 了!
println!("Running for loop:");
for number in counter {
println!("{}", number);
}
// 注意:`for` 循環(huán)會(huì)“消耗掉”迭代器。
// 如果想再用一次,需要重新創(chuàng)建:
let counter2 = Counter::new(3);
// 你也可以手動(dòng)調(diào)用 next() 看看發(fā)生了什么
println!("\nManual next() calls:");
let mut counter3 = Counter::new(2); // 必須是 mut,因?yàn)?next() 需要 &mut self
println!("{:?}", counter3.next()); // Some(1)
println!("{:?}", counter3.next()); // Some(2)
println!("{:?}", counter3.next()); // None (迭代結(jié)束)
println!("{:?}", counter3.next()); // None (之后永遠(yuǎn)是 None)
}
輸出:
Running for loop: 1 2 3 4 5 Manual next() calls: Some(1) Some(2) None None
你已經(jīng)掌握了 80% 的精髓了!太棒了!??
4. 實(shí)踐二:讓自定義結(jié)構(gòu)體“可迭代” ??
在實(shí)踐一中,Counter 本身就是迭代器。但更常見的情況是:你有一個(gè)集合(比如 `Myook),你想**為它創(chuàng)建一個(gè)迭代器**(比如 BookPageIterator`)。
就像 Vec (集合) 和 VecIter (它的迭代器) 的關(guān)系一樣。
我們希望實(shí)現(xiàn)這樣的效果:
let my_list = MyList::new();
for item in &my_list { // 注意這里是 &my_list
// ...
}
要實(shí)現(xiàn)這個(gè),我們需要兩個(gè) Trait:Iterator (老朋友) 和 IntoIterator (新朋友)。
IntoIterator Trait 就像一個(gè)“轉(zhuǎn)換器”,它告訴 for 循環(huán):“嘿,我知道如何把我(&MyList)轉(zhuǎn)換成一個(gè)真正的迭代器!”
第 1 步:定義集合和它的迭代器結(jié)構(gòu)體
// 我們的集合
struct MyList {
items: Vec<String>,
}
impl MyList {
fn new() -> Self {
Self {
items: vec![
"Rust".to_string(),
"is".to_string(),
"Awesome".to_string(),
],
}
}
}
// ------------------------------------
// 專門為 MyList 服務(wù)的迭代器結(jié)構(gòu)體
// 它需要“借用” MyList 的數(shù)據(jù)
// 'a 是生命周期,表示它借用的數(shù)據(jù)至少和 'a 活得一樣久
struct MyListIter<'a> {
list: &'a MyList, // 持有對(duì) MyList 的引用
index: usize, // 跟蹤迭代到第幾個(gè)了
}
第 2 步:為 `MyListIter 實(shí)現(xiàn)Iterator
這和 Counter 的例子幾乎一樣,只是現(xiàn)在我們是從 Vec 中取數(shù)據(jù)。
// 'a 也要在這里聲明
impl<'a> Iterator for MyListIter<'a> {
// 這一次,我們迭代的是對(duì) String 的引用
type Item = &'a String;
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.list.items.len() {
// 還有元素
let item = &self.list.items[self.index];
self.index += 1;
Some(item)
} else {
// 沒元素了
None
}
}
}
第 3 步:關(guān)鍵!為MyList實(shí)現(xiàn)IntoIterator
這是連接 for 循環(huán)和 MyListIter 的“膠水”。我們希望 for item in &my_list 能工作,所以我們要為 &MyList 實(shí)現(xiàn) IntoIterator。
// 為 &MyList (對(duì) MyList 的不可變引用) 實(shí)現(xiàn) IntoIterator
impl<'a> IntoIterator for &'a MyList {
// 迭代項(xiàng)還是 &String
type Item = &'a String;
// 告訴 for 循環(huán):你調(diào)用 into_iter() 時(shí),
// 我會(huì)返回一個(gè) MyListIter<'a> 實(shí)例
type IntoIter = MyListIter<'a>;
// `for` 循環(huán)會(huì)自動(dòng)調(diào)用這個(gè)方法!
// 這里的 self 就是 &'a MyList
fn into_iter(self) -> Self::IntoIter {
// 創(chuàng)建我們剛才定義的迭代器實(shí)例
MyListIter {
list: self, // self 就是 &MyList
index: 0, // 從 0 開始
}
}
}
第 4 步:見證奇跡!
fn main() {
let my_list = MyList::new();
// 感謝 IntoIterator,這行代碼現(xiàn)在可以完美工作了!
// 1. `for` 循環(huán)看到 &my_list
// 2. 它調(diào)用 (&my_list).into_iter()
// 3. 我們的代碼返回了一個(gè) MyListIter
// 4. `for` 循環(huán)不斷調(diào)用 MyListIter.next()
for item in &my_list {
println!("Item: {}", item);
}
}
輸出:
Item: Rust
Item: is
Item: Awesome
你做到了!這已經(jīng)是 Rust 中非常地道的迭代器實(shí)現(xiàn)方式了!??
5. 你免費(fèi)獲得的“超能力” ??
最爽的部分來了!
當(dāng)你辛辛苦苦地實(shí)現(xiàn)了 Iterator Trait(哪怕只寫了 next() 方法),Rust 編譯器會(huì)免費(fèi)贈(zèng)送給你一大堆超級(jí)好用的“迭代器適配器” (Iterator Adapters)!
比如 .map(), .filter(), .zip(), .sum(), .collect()… 全都能用了!
看看我們剛才的 Counter:
let sum: u32 = Counter::new(5) // 我們的迭代器 (1, 2, 3, 4, 5)
.zip(Counter::new(5).skip(1)) // ( (1,2), (2,3), (3,4), (4,5) )
.map(|(a, b)| a * b) // ( 2, 6, 12, 20 )
.filter(|x| *x > 10) // ( 12, 20 )
.sum(); // 12 + 20 = 32
println!("The complex sum is: {}", sum); // 32
我們只寫了 next(),但 zip, skip, map, filter, sum 都能在我們的 Counter 上使用!這就是 Rust Trait 和迭代器模式的強(qiáng)大之處!
6. 總結(jié) & 下一步
我們來回顧一下關(guān)鍵點(diǎn):
- 迭代器是任何實(shí)現(xiàn)了 Iterator Trait 的東西。
- Iterator Trait 的核心是 type Item; (迭代什么) 和 `fn next(&mut self) -> OptionSelf::Item 你需要一個(gè) struct 來保存迭代的狀態(tài) (比如 current 索引)。
- `next)方法通過返回Some(value)來提供值,通過返回None` 來停止迭代。
- 要讓你自己的集合(如 MyList)支持 for item in &collection,你需要為 &collection 實(shí)現(xiàn) IntoIterator Trait,讓它返回你自定義的迭代器(如 MyListIter)。
- 一旦實(shí)現(xiàn)了 Iterator,你就免費(fèi)獲得了所有適配器 (map, `filter …)。
到此這篇關(guān)于rust 自定義迭代器的實(shí)現(xiàn)方法的文章就介紹到這了,更多相關(guān)rust 自定義迭代器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Rust語言從入門到精通之Tokio的Channel深入理解
這篇文章主要為大家介紹了Rust語言從入門到精通之Tokio的Channel深入理解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05
Rust練習(xí)冊(cè)之字母異位詞與字符串處理方法技巧
Rust作為一種系統(tǒng)編程語言,其在字符串拼接方面的設(shè)計(jì)既靈活又高效,這篇文章主要介紹了Rust練習(xí)冊(cè)之字母異位詞與字符串處理方法技巧的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2026-02-02

