疊代器和擁有權
Rust 的擁有權模型會影響許多 API。Iterator 和 IntoIterator 特徵就是一例。
Iterator
特徵就像介面一樣,可以說明型別的行為 (方法)。Iterator 特徵就是指您可以呼叫 next,直到取回 None 為止:
#![allow(unused)] fn main() { pub trait Iterator { type Item; fn next(&mut self) -> Option<Self::Item>; } }
您可以像下方這樣使用這個特徵:
fn main() { let v: Vec<i8> = vec![10, 20, 30]; let mut iter = v.iter(); println!("v[0]: {:?}", iter.next()); println!("v[1]: {:?}", iter.next()); println!("v[2]: {:?}", iter.next()); println!("No more items: {:?}", iter.next()); }
如要瞭解疊代器傳回的型別為何,不妨在這裡測試答案:
fn main() { let v: Vec<i8> = vec![10, 20, 30]; let mut iter = v.iter(); let v0: Option<..> = iter.next(); println!("v0: {v0:?}"); }
思考一下,為什麼會使用這種型別?
IntoIterator
Iterator 特徵會告訴您如何在建立疊代器後進行「疊代」。相關特徵 IntoIterator 則會說明如何建立疊代器:
#![allow(unused)] fn main() { pub trait IntoIterator { type Item; type IntoIter: Iterator<Item = Self::Item>; fn into_iter(self) -> Self::IntoIter; } }
這裡的語法表示每個 IntoIterator 的實作都必須宣告兩種型別:
Item:進行疊代的型別,例如i8。IntoIter:into_iter方法傳回的Iterator型別。
請注意,IntoIter 和 Item 已建立連結:疊代器必須具有相同的 Item 型別,表示會傳回 Option<Item>。
和先前一樣,思考疊代器傳回的型別為何。
fn main() { let v: Vec<String> = vec![String::from("foo"), String::from("bar")]; let mut iter = v.into_iter(); let v0: Option<..> = iter.next(); println!("v0: {v0:?}"); }
for 迴圈
現在我們已瞭解 Iterator 和 IntoIterator,可以建構 for 迴圈了。這會在運算式上呼叫 into_iter(),並對產生的疊代器進行疊代:
fn main() { let v: Vec<String> = vec![String::from("foo"), String::from("bar")]; for word in &v { println!("word: {word}"); } for word in v { println!("word: {word}"); } }
思考一下,每個迴圈中的 word 型別為何?
請用上方的程式碼進行試驗,並參閱 impl IntoIterator for &Vec<T> 和 impl IntoIterator for Vec<T> 的說明文件確認答案。