Rust中如何以惯用方式过滤嵌套可迭代类型的唯一性?
问题:过滤嵌套向量中含重复元素的子向量
假设有一个嵌套向量vec_of_vecs = vec![vec![1,2],vec![1,3],vec![2,2],vec![2,3]],需要用Rust惯用方式过滤掉其中的vec。
尝试代码
use std::collections::HashSet; use std::hash::Hash; fn filter_out_duplicates(vec_of_vecs: Vec<Vec<u8>>) -> Vec<Vec<u8>> { vec_of_vecs .into_iter() .filter(all_unique) .collect() } pub fn all_unique<T>(iterable: T) -> bool where T: IntoIterator, T::Item: Eq + Hash, { let mut unique = HashSet::new(); iterable.into_iter().all(|x| unique.insert(x)) }
编译错误信息
the method `collect` exists for struct `std::iter::Filter<std::vec::IntoIter<std::vec::Vec<u8>>, fn(&std::vec::Vec<u8>) -> bool {all_unique::<&std::vec::Vec<u8>>}`, but its trait bounds were not satisfied the following trait bounds were not satisfied: `<fn(&std::vec::Vec<u8>) -> bool {all_unique::<&std::vec::Vec<u8>>} as std::ops::FnOnce<(&std::vec::Vec<u8>,)>>::Output = bool` which is required by `std::iter::Filter<std::vec::IntoIter<std::vec::Vec<u8>>, fn(&std::vec::Vec<u8>) -> bool {all_unique::<&std::vec::Vec<u8>>}: std::iter::Iterator` `fn(&std::vec::Vec<u8>) -> bool {all_unique::<&std::vec::Vec<u8>>}: std::ops::FnMut<(&std::vec::Vec<u8>,)>` which is required by `std::iter::Filter<std::vec::IntoIter<std::vec::Vec<u8>>, fn(&std::vec::Vec<u8>) -> bool {all_unique::<&std::vec::Vec<u8>>}: std::iter::Iterator` `std::iter::Filter<std::vec::IntoIter<std::vec::Vec<u8>>, fn(&std::vec::Vec<u8>) -> bool {all_unique::<&std::vec::Vec<u8>>}: std::iter::Iterator` which is required by `&mut std::iter::Filter<std::vec::IntoIter<std::vec::Vec<u8>>, fn(&std::vec::Vec<u8>) -> bool {all_unique::<&std::vec::Vec<u8>>}: std::iter::Iterator`rustcE0599 filter.rs(15, 1): doesn't satisfy `_: std::iter::Iterator`
错误原因分析
核心问题有两点:
filter方法传递给谓词的是子向量的引用(&Vec<u8>),直接将泛型函数all_unique作为函数指针传入时,编译器无法推导HashSet的具体类型(泛型函数转函数指针要求所有类型参数完全明确)。- 虽然
all_unique的实现本身支持处理&Vec<u8>(可转为迭代&u8的迭代器),但函数指针的类型推导环节卡住了。
惯用修复方案
方案一:用闭包包装调用(最简修复)
通过闭包包装all_unique的调用,帮助编译器推导类型,无需修改all_unique的实现:
use std::collections::HashSet; use std::hash::Hash; fn filter_out_duplicates(vec_of_vecs: Vec<Vec<u8>>) -> Vec<Vec<u8>> { vec_of_vecs .into_iter() .filter(|v| all_unique(v)) // 闭包辅助类型推导 .collect() } pub fn all_unique<T>(iterable: T) -> bool where T: IntoIterator, T::Item: Eq + Hash, { let mut unique = HashSet::new(); iterable.into_iter().all(|x| unique.insert(x)) }
方案二:明确传递迭代器(更清晰)
调整all_unique接收迭代器类型,然后在filter中明确传递子向量的迭代器,避免类型推导歧义:
use std::collections::HashSet; use std::hash::Hash; fn filter_out_duplicates(vec_of_vecs: Vec<Vec<u8>>) -> Vec<Vec<u8>> { vec_of_vecs .into_iter() .filter(|v| all_unique(v.iter())) // 明确传递子向量的迭代器 .collect() } pub fn all_unique<I>(iter: I) -> bool where I: Iterator, I::Item: Eq + Hash, { let mut unique = HashSet::new(); iter.all(|x| unique.insert(x)) }
两种方案都不需要克隆子向量,符合Rust零成本抽象的惯用风格,最终都会正确过滤掉vec![2,2],保留其余子向量。
内容的提问来源于stack exchange,提问作者financial_physician
相关产品推荐
相关产品推荐

