Rust for cpp devs - 迭代器

迭代器(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);
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容