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
Iteratoris 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
相关产品推荐
相关产品推荐

