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

Rust如何向函数传入可迭代对象并完成两次遍历

我有如下Rust函数:

fn do_stuff(values: HashSet<String>) {
  // Count stuff
  for s in values.iter() {
    prepare(s);
  }
  // Process stuff 
  for s in values.iter() {
    process(s);
  }
}

该函数运行正常,但单元测试时我需要传入元素顺序固定的集合(处理顺序不符就无法覆盖目标测试用例)。HashSet不保证元素顺序,所以我希望函数也能接收Vec作为入参。

我想将参数改为可迭代类型,但Rust中只有IntoIter trait可用,我尝试编写如下代码:

fn do_stuff<C>(values: C)
where C: IntoIterator<Item=String>
 {
  // Count stuff
  for s in values {
    prepare(s);
  }
  // Process stuff 
  for s in values {
    process(s);
  }
}

编译失败,原因是第一次遍历已经消耗了values。编译器建议借用values,我修改代码如下:

fn do_stuff<C>(values: C)
where C: IntoIterator<Item=String>
 {
  // Count stuff
  for s in &values {
    prepare(s);
  }
  // Process stuff 
  for s in values {
    process(s);
  }
}

编译报错:

the trait Iterator is not implemented for &C

我可以通过clone实现需求,但实际数据集体积很大,希望尽量避免拷贝。我也可以接受将函数签名调整为do_stuff(values: &C),只要能解决问题即可。

Stack Overflow上的相关问题多为生命周期问题,与我遇到的场景不符。另有一个为引用实现Iterable trait的方案,我尝试实现:

pub trait Iterable {
    type Item;
    type Iter: Iterator<Item = Self::Item>;
    fn iterator(&self) -> Self::Iter;
}

impl Iterable for HashSet<String> {
    type Item = String;
    type Iter = HashSet<String>::Iterator;
    fn iterator(&self) -> Self::Iter {
        self.iter()
    }
}

编译报错E0223:关联类型歧义,编译器提示使用完全限定语法,我按提示修改后:

impl Iterable for HashSet<String> {
    type Item = String;
    type Iter = <HashSet<std::string::String> as Trait>::Iterator;
    fn iterator(&self) -> Self::Iter {
        self.iter()
    }
}

又报错E0433:未声明类型Trait,将Trait替换为HashSet后,编译器无法识别表达式末尾的Iterator或IntoIter关联类型。

采纳答案的实现版本

我按照@eggyal的答案实现了可编译版本:

use std::collections::HashSet;

fn do_stuff<I>(iterable: I)
where
    I: IntoIterator + Copy,
    I::Item: AsRef<str>,
{
    // Count stuff
    for s in iterable {
        prepare(s.as_ref());
    }
    // Process stuff
    for s in iterable {
        process(s.as_ref());
    }
}

fn prepare(s: &str) {
    println!("prepare: {}", s)
}
fn process(s: &str) {
    println!("process: {}", s)
}

#[cfg(test)]
mod test_cluster {
    use super::*;

    #[test]
    fn doit() {
        let vec: Vec<String> = vec!["a".to_string(), "b".to_string(), "c".to_string()];
        let set = vec.iter().cloned().collect::<HashSet<_>>();
        do_stuff(&vec);
        do_stuff(&set);
    }
}

运行测试输出如下:

---- simple::test_cluster::doit stdout ----
prepare: a
prepare: b
prepare: c
process: a
process: b
process: c
prepare: c
prepare: b
prepare: a
process: c
process: b
process: a

内容的提问来源于stack exchange,提问作者Troy Daniels

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 13:12:03