Rust中如何统一切片迭代器与反向迭代器的类型?
Rust:在Vec中混合存放正向和反向切片迭代器(不收集元素)
问题场景
想要创建一个Vec,同时存放切片的正向迭代器和反向迭代器,编写了如下代码:
let mut output = Vec::new(); let input = b"1234567890"; let cuts = [(0,1), (1,3), (3, 5)]; for (start, end) in cuts{ output.push(input[start..end].iter()); output.push(input[start..end].iter().rev()); }
编译时出现错误:
expected struct `std::slice::Iter`, found struct `Rev`
已知错误原因是Iter和Rev<Iter>是不同的具体类型,Vec要求所有元素类型一致,希望找到不收集元素的情况下统一类型的方案,且尝试过.iter().rev().rev()仍无法解决(因为其类型为Rev<Rev<Iter>>,仍与前两者不同)。
解决方案
方法1:使用 trait object(动态分发)
将迭代器装箱为Box<dyn Iterator<Item=&u8>>,利用Rust的 trait 对象特性,让不同的迭代器类型统一到同一个 trait 对象类型下:
let mut output: Vec<Box<dyn Iterator<Item = &u8>>> = Vec::new(); let input = b"1234567890"; let cuts = [(0,1), (1,3), (3, 5)]; for (start, end) in cuts { // 将正向迭代器装箱 output.push(Box::new(input[start..end].iter())); // 将反向迭代器装箱 output.push(Box::new(input[start..end].iter().rev())); }
说明:这种方法通过动态分发实现类型统一,会带来少量运行时开销,但完全满足不收集元素的需求,代码实现简单。
方法2:自定义枚举类型(静态分发)
如果追求无运行时开销的静态分发,可以定义一个枚举来覆盖两种迭代器类型,并为其实现Iterator trait:
// 定义枚举,包含正向和反向迭代器类型 enum SliceIter<'a> { Forward(std::slice::Iter<'a, u8>), Reverse(std::iter::Rev<std::slice::Iter<'a, u8>>), } // 为枚举实现Iterator trait impl<'a> Iterator for SliceIter<'a> { type Item = &'a u8; fn next(&mut self) -> Option<Self::Item> { match self { SliceIter::Forward(iter) => iter.next(), SliceIter::Reverse(iter) => iter.next(), } } } // 使用示例 let mut output: Vec<SliceIter> = Vec::new(); let input = b"1234567890"; let cuts = [(0,1), (1,3), (3, 5)]; for (start, end) in cuts { output.push(SliceIter::Forward(input[start..end].iter())); output.push(SliceIter::Reverse(input[start..end].iter().rev())); }
说明:这种方法是静态分发,没有运行时开销,但需要手动实现Iterator trait,适合对性能要求较高的场景。
补充说明
.iter().rev().rev()无法解决问题的原因是:.iter()的类型是std::slice::Iter,.iter().rev()是std::iter::Rev<std::slice::Iter>,而.iter().rev().rev()是std::iter::Rev<std::iter::Rev<std::slice::Iter>>——这三者都是不同的具体类型,Vec无法同时存储不同的具体类型,因此必须通过上述两种方法将其统一为同一类型。
内容的提问来源于stack exchange,提问作者George Shuklin
相关产品推荐
相关产品推荐

