You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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 |&current_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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 09:54:59