Rust实现类似C++ std::views::split的迭代器拆分适配器方法
无Box的实现方案
核心思路
你遇到的两个问题本质上都可以通过自定义迭代器结构体解决,完全不需要用到动态分发的Box<dyn Iterator>:
- 避开标准库
TakeWhile依赖闭包导致类型无法命名的问题,单独实现子迭代器结构体,内置分隔符判断逻辑 - 子迭代器持有父迭代器的可变引用,生命周期和父实例绑定,由编译器自动校验安全性
完整实现代码
use std::iter::Peekable; // 子迭代器类型,每次split返回的就是这个结构体的实例 struct SplitIter<'a, I, T> where I: Iterator, { iter: &'a mut Peekable<I>, sep: &'a T, ended: bool, } impl<'a, I, T> Iterator for SplitIter<'a, I, T> where I: Iterator, I::Item: PartialEq<T>, { type Item = I::Item; fn next(&mut self) -> Option<Self::Item> { if self.ended { return None; } match self.iter.next() { None => { self.ended = true; None } Some(item) => { if item == *self.sep { self.ended = true; None } else { Some(item) } } } } } // 父迭代器类型 struct Split<I, T> where I: Iterator, { iter: Peekable<I>, sep: T, } impl<I, T> Split<I, T> where I: Iterator, { fn new(iter: I, sep: T) -> Self { Self { iter: iter.peekable(), sep, } } } impl<I, T> Iterator for Split<I, T> where I: Iterator, I::Item: PartialEq<T>, { type Item = SplitIter<'_, I, T>; fn next(&mut self) -> Option<Self::Item> { // 跳过所有连续分隔符 loop { match self.iter.peek() { None => return None, Some(item) if item == &self.sep => { self.iter.next(); } _ => break, } } // 返回新的子迭代器 Some(SplitIter { iter: &mut self.iter, sep: &self.sep, ended: false, }) } } // 对外暴露的入口函数 fn iter_split<I, T>(iter: I, sep: T) -> Split<I, T> where I: Iterator, I::Item: PartialEq<T>, { Split::new(iter, sep) } // 测试代码 fn main() { let v = vec![1, 2, 3, 0, 1, 2, 0, 4, 5, 0]; for inner_iter in iter_split(v.iter(), &0) { inner_iter.for_each(|x| print!("{} ", x)); println!(); } }
代码说明
- 全程静态类型无动态分发,性能和标准库迭代器完全一致,没有额外开销
- 自动处理连续分隔符、首尾分隔符的边界场景,和你给出的预期行为完全匹配
- 子迭代器是惰性求值的,只有实际遍历的时候才会消耗底层迭代器的元素,符合Rust迭代器的设计惯例
- 编译器会自动保证你必须消费完前一个子迭代器才能获取下一个,不会出现多个子迭代器同时竞争底层迭代器的问题
测试输出
和你给出的预期完全一致:
1 2 3 1 2 4 5
内容的提问来源于stack exchange,提问作者nightuser
相关产品推荐
相关产品推荐

