如何在Rust中为迭代器实现类似slice.windows()的功能?
在Rust中为迭代器实现类似
windows()的功能(无需collect()) 方案一:仅用核心标准库实现
无需自定义复杂的迭代器包装类型,借助std::collections::VecDeque和Iterator::scan方法就能实现,空间复杂度仅为O(窗口大小),不需要提前收集整个迭代器:
use std::collections::VecDeque; fn iterator_windows<I: Iterator>(mut iter: I, window_size: usize) -> impl Iterator<Item = VecDeque<I::Item>> { // 初始化窗口,预分配容量避免频繁扩容 let mut window = VecDeque::with_capacity(window_size); // 填充初始窗口 for _ in 0..window_size { match iter.next() { Some(item) => window.push_back(item), None => break, } } // 初始窗口不足指定大小则直接返回空迭代器 if window.len() < window_size { return std::iter::empty(); } // 先输出初始窗口,再通过scan迭代更新窗口 std::iter::once(window.clone()).chain(iter.scan(window, |win, item| { win.pop_front(); win.push_back(item); Some(win.clone()) })) } // 使用示例 fn main() { let my_vec = vec![1, 2, 3, 4, 5]; let bar = my_vec.iter(); for win in iterator_windows(bar, 3) { println!("{:?}", win); // 依次输出 [1, 2, 3], [2, 3, 4], [3, 4, 5] } }
方案二:用itertools实现更简洁的代码
如果可以使用Rust生态的常用工具库itertools,它提供了现成的tuple_windows(固定大小窗口)和windows(动态大小窗口)方法,完全满足需求:
use itertools::Itertools; fn main() { let my_vec = vec![1, 2, 3, 4, 5]; let bar = my_vec.iter(); // 固定大小为3的窗口,返回元组(&i32, &i32, &i32) for win in bar.tuple_windows() { println!("{:?}", win); // 依次输出 (1, 2, 3), (2, 3, 4), (3, 4, 5) } // 动态大小窗口,返回子迭代器,可收集为Vec使用 let bar2 = my_vec.iter(); for win in bar2.windows(3) { println!("{:?}", win.collect::<Vec<_>>()); // 依次输出 [1, 2, 3], [2, 3, 4], [3, 4, 5] } }
关键说明
- 核心标准库实现通过
VecDeque维护滑动窗口,每次迭代仅执行弹出头部、压入尾部的操作,效率高且内存占用可控。 itertools是Rust社区广泛使用的工具库,其窗口方法经过优化,代码更简洁,适合大多数日常开发场景。
内容的提问来源于stack exchange,提问作者Umberto Fontanazza
相关产品推荐
相关产品推荐

