2.4 IntoIter

原文链接: https://rust-unofficial.github.io/too-many-lists/second-into-iter.html

在 Rust 中,集合通过 Iterator trait 来迭代。它比 Drop 稍微复杂一点:

1
2
3
4
pub trait Iterator {
    type Item;
    fn next(&mut self) -> Option<Self::Item>;
}

这里的新面孔是 type Item。它声明每个 Iterator 实现都有一个名为 Item 的关联类型。在这里,就是调用 next 时能吐出的类型。

Iterator 返回 Option<Self::Item> 的原因,是把 has_next 和 get_next 合并了。有下一个值时返回 Some(value),没有时返回 None。这让 API 总体上更易用、更安全,也避免了 has_next 和 get_next 之间冗余的检查和逻辑。不错!

可惜 Rust 还没有类似 yield 的语句(至少目前还没有),所以逻辑得自己写。另外,每个集合其实应该尽量实现三种迭代器:

  • IntoIter — T
  • IterMut — &mut T
  • Iter — &T

用 List 的接口实现 IntoIter,我们其实已经有全部工具了:反复调用 pop 就行。因此把 IntoIter 实现为 List 的 newtype 包装:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// 元组结构体是结构体的另一种形式,
// 适合对其他类型的简单包装。
pub struct IntoIter<T>(List<T>);

impl<T> List<T> {
    pub fn into_iter(self) -> IntoIter<T> {
        IntoIter(self)
    }
}

impl<T> Iterator for IntoIter<T> {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        // 用数字索引访问元组结构体的字段
        self.0.pop()
    }
}

写个测试:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#[test]
fn into_iter() {
    let mut list = List::new();
    list.push(1); list.push(2); list.push(3);

    let mut iter = list.into_iter();
    assert_eq!(iter.next(), Some(3));
    assert_eq!(iter.next(), Some(2));
    assert_eq!(iter.next(), Some(1));
    assert_eq!(iter.next(), None);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
> cargo test

     Running target/debug/lists-5c71138492ad4b4a

running 4 tests
test first::test::basics ... ok
test second::test::basics ... ok
test second::test::into_iter ... ok
test second::test::peek ... ok

test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured

不错!

最后修改 August 23, 2026: 更新 (499855b16)