如何使用Rust迭代器查找并返回切片的指定范围?
使用Rust迭代器实现切片分段提取(以首个0为终止符)
要实现你描述的需求——反复从切片中提取从当前起始位置到首个0(包含该0)的子切片,直到处理完所有元素,可以通过两种方式实现:自定义迭代器,或使用标准库的迭代器适配器。
方式一:自定义迭代器(直观清晰)
自定义一个迭代器结构体来跟踪当前处理的位置,每次调用next()时完成分段提取和位置更新:
struct SplitOnFirstZero<'a, T: PartialEq> { src: &'a [T], current_pos: usize, } impl<'a, T: PartialEq> SplitOnFirstZero<'a, T> { // 创建迭代器实例 fn new(src: &'a [T]) -> Self { SplitOnFirstZero { src, current_pos: 0, } } } // 实现Iterator trait impl<'a, T: PartialEq> Iterator for SplitOnFirstZero<'a, T> { type Item = &'a [T]; fn next(&mut self) -> Option<Self::Item> { // 所有元素处理完毕,返回None if self.current_pos >= self.src.len() { return None; } let remaining = &self.src[self.current_pos..]; match remaining.iter().position(|&val| val == 0) { // 找到0,提取从current_pos到0的位置(包含),更新current_pos到0的下一位 Some(zero_idx) => { let end_pos = self.current_pos + zero_idx + 1; let segment = &self.src[self.current_pos..end_pos]; self.current_pos = end_pos; Some(segment) } // 未找到0,提取剩余所有元素,将current_pos移到末尾 None => { let segment = &self.src[self.current_pos..]; self.current_pos = self.src.len(); Some(segment) } } } }
使用示例
fn main() { let src = &[7, 4, 5, 0, 3, 6, 0, 2, 5]; for segment in SplitOnFirstZero::new(src) { println!("{segment:?}"); } }
输出结果:
[7, 4, 5, 0] [3, 6, 0] [2, 5]
方式二:使用标准库迭代器适配器(简洁)
利用successors和scan适配器组合,无需自定义结构体即可实现需求:
fn split_on_first_zero<'a, T: PartialEq + 'a>(src: &'a [T]) -> impl Iterator<Item = &'a [T]> + 'a { // 生成每次分段结束的位置序列 std::iter::successors(Some(0), move |¤t_pos| { if current_pos >= src.len() { None } else { let remaining = &src[current_pos..]; // 找到0则返回下一个起始位置,否则返回切片末尾位置 remaining.iter().position(|&val| val == 0) .map(|idx| current_pos + idx + 1) .or_else(|| Some(src.len())) } }) // 扫描位置序列,生成对应的子切片 .scan(0, |prev_pos, next_pos| { let segment = &src[*prev_pos..next_pos]; *prev_pos = next_pos; Some(segment) }) // 过滤空切片(避免最后一次返回空) .take_while(|segment| !segment.is_empty()) }
使用示例
fn main() { let src = &[7, 4, 5, 0, 3, 6, 0, 2, 5]; for segment in split_on_first_zero(src) { println!("{segment:?}"); } }
输出结果与方式一完全一致。
两种方式对比
- 自定义迭代器:代码结构清晰,逻辑一目了然,便于后续扩展(比如支持自定义分隔符)。
- 迭代器适配器:代码更紧凑,无需定义新类型,适合快速实现简单需求。
内容的提问来源于stack exchange,提问作者rodrigocfd
相关产品推荐
相关产品推荐

