迭代器(Iterator)可以允許對(duì)序列中的每一個(gè)元素執(zhí)行某個(gè)操作。
Rust 的迭代器分為三種:
-
iter()返回一個(gè)常量引用,不可改變?cè)氐闹?/li> -
iter_mut()返回一個(gè)可變引用,能夠修改元素的值 -
into_iter()會(huì)拿走容器的 ownership
Iterator Trait
迭代器實(shí)現(xiàn)了 Iterator trait,定義如下(type Item 的用法在后面例子中會(huì)講):
pub trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
// methods with default implementations elided
}
Iterator trait 要求必須實(shí)現(xiàn) next 方法,它返回一個(gè)封裝在 Some 中的元素,如果沒有下一個(gè)元素,則返回 None。之所以要求必須實(shí)現(xiàn) next,是因?yàn)?Iterator 默認(rèn)實(shí)現(xiàn)的某些其他方法會(huì)調(diào)用。
例如:
#[cfg(test)]
mod tests {
#[test]
fn iterator_demonstration() {
let v1 = vec![1, 2, 3];
let mut v1_iter = v1.iter();
assert_eq!(v1_iter.next(), Some(&1));
assert_eq!(v1_iter.next(), Some(&2));
assert_eq!(v1_iter.next(), Some(&3));
assert_eq!(v1_iter.next(), None);
}
}
值得注意的是迭代器變量定義為 mut,因?yàn)槊看握{(diào)用 next 都會(huì)修改迭代器指向下一個(gè)元素。
消耗 Iterator
Iterator trait 中調(diào)用 next 的方法稱為 consuming adaptors。因?yàn)槭褂眠@些方法會(huì)“耗盡”這個(gè)迭代器,例如 sum。由于迭代器都是惰性的,必須使用 consuming adaptors 才能得到運(yùn)行結(jié)果。
#[test]
fn iterator_sum() {
let v1 = vec![1, 2, 3];
let v1_iter = v1.iter();
let total: u32 = v1_iter.sum();
assert_eq!(total, 6);
}
此后無(wú)法再使用 v1_iter,因?yàn)?code>sum 已經(jīng)拿走了它的 ownership。
生成 Iterator
除了消耗 Iterator 的, 也有生成 Iterator 的方法,稱為 iterator adaptors。但是生成后的 Iterator 上必須使用 consuming adaptors 來得到結(jié)果。
例如,map 方法可以將舊的 iterator 映射到一個(gè)新的 iterator。下面的代碼將 v1 中的每個(gè)元素加 1 并生成一個(gè) v2。注意,map 只是做了 iterator 的映射,并不是直接把 v1 變成 v2。
#[test]
fn iterator_map() {
let v1 = vec![1, 2, 3];
let v1_iter = v1.iter();
let v2_iter = v1_iter.map(|x| {x + 1});
let v2: Vec<_> = v2_iter.collect();
assert_eq!(v2, vec![2, 3, 4]);
}
還有一個(gè)常用的 iterator adapter 是 filter 方法:
#[derive(PartialEq, Debug)]
struct Shoe {
size: u32,
style: String,
}
fn shoes_in_my_size(shoes: Vec<Shoe>, shoe_size: u32) -> Vec<Shoe> {
shoes.into_iter().filter(|s| s.size == shoe_size).collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn filters_by_size() {
let shoes = vec![
Shoe {
size: 10,
style: String::from("sneaker"),
},
Shoe {
size: 13,
style: String::from("sandal"),
},
Shoe {
size: 10,
style: String::from("boot"),
},
];
let in_my_size = shoes_in_my_size(shoes, 10);
assert_eq!(
in_my_size,
vec![
Shoe {
size: 10,
style: String::from("sneaker")
},
Shoe {
size: 10,
style: String::from("boot")
},
]
);
}
}
shoes_in_my_size 函數(shù)篩選出所有大小為 10 的鞋。filter 也是一個(gè)從 iterator 到 iterator 的映射。在這里,我們使用 into_iter 拿走了原來的容器的 ownership。
自定義 Iterator
我們定義了一個(gè)計(jì)數(shù)器類:
struct Counter {
count: u32,
}
impl Counter {
fn new() -> Counter {
return Counter{count: 0};
}
}
然后讓它實(shí)現(xiàn) Iterator trait,計(jì)數(shù)到 5 終止:
impl Iterator for Counter {
type Item = u32; // call to next() will return Option<u32>
fn next(&mut self) -> Option<Self::Item> {
if self.count < 5 {
self.count += 1;
return Some(self.count);
}
return None; // return None when iteration ends
}
}
這里值得注意的點(diǎn)已經(jīng)在注釋中標(biāo)出。測(cè)試代碼如下:
#[test]
fn test_counter() {
let mut counter = Counter::new();
assert_eq!(counter.next(), Some(1));
assert_eq!(counter.next(), Some(2));
assert_eq!(counter.next(), Some(3));
assert_eq!(counter.next(), Some(4));
assert_eq!(counter.next(), Some(5));
assert_eq!(counter.next(), None);
}