如何在Rust中使用Vec实现过滤?编译错误原因及解决方案
如何在Rust中过滤Vec并返回新的Vec?
咱们一步步拆解你遇到的问题,再给出针对性的解决办法:
错误原因分析
你碰到的两个编译错误本质都是类型不匹配导致的:
&&i64无法与i64比较:
调用wordIds.iter()时,返回的迭代器会产生对Vec中元素的引用(也就是&i64类型)。而filter方法的闭包参数是对迭代器元素的引用,也就是&&i64。你直接拿这个双重引用和current_word_id(i64类型)比较,Rust找不到对应的比较实现,自然报错。无法从
&i64迭代器构建Vec<i64>:collect要求迭代器的元素类型能转换成目标容器的元素类型。你的迭代器输出的是&i64,但要收集成Vec<i64>,Rust没有默认实现这种转换,必须显式把引用转换成值才行。
修正方案
这里有几种常用的修正方式,你可以根据需求选择:
方案1:保留原Vec所有权(推荐)
如果你还需要继续使用原 wordIds,可以用 iter() 配合 copied()(或 cloned()),同时修正闭包中的类型匹配:
fn main() { let current_word_id: i64 = 1; let wordIds: Vec<i64> = vec![1, 2, 1, 3]; // 示例数据 let current_sentences: Vec<i64> = wordIds .iter() .filter(|&&sen| sen == current_word_id) // 双重解引用拿到i64类型的值 .copied() // 把&i64复制成i64(i64实现了Copy trait) .collect(); println!("过滤结果: {:?}", current_sentences); // 输出 [1, 1] }
- 对于没有实现
Copy的类型(比如自定义结构体),把copied()换成cloned()即可。 - 你也可以用
|sen| **sen == current_word_id代替|&&sen| sen == current_word_id,效果完全一致。
方案2:消耗原Vec
如果你不需要再使用原 wordIds,可以用 into_iter() 直接获取元素的所有权,这样就不用处理引用的麻烦:
fn main() { let current_word_id: i64 = 1; let wordIds: Vec<i64> = vec![1, 2, 1, 3]; let current_sentences: Vec<i64> = wordIds .into_iter() .filter(|sen| *sen == current_word_id) // 单次解引用拿到i64 .collect(); println!("过滤结果: {:?}", current_sentences); // 输出 [1, 1] // 注意:这里wordIds已经被消耗,不能再使用了 }
方案3:用map转换类型
和方案1类似,你可以用 map 把引用转换成值,替代 copied():
fn main() { let current_word_id: i64 = 1; let wordIds: Vec<i64> = vec![1, 2, 1, 3]; let current_sentences: Vec<i64> = wordIds .iter() .filter(|&&sen| sen == current_word_id) .map(|&x| x) // 把&i64转换成i64 .collect(); }
Rust中过滤Vec的通用思路
针对不同场景,通用的过滤流程可以总结为:
- 选择迭代方式:
- 需要保留原Vec:用
iter()(产生引用) - 不需要原Vec:用
into_iter()(产生所有权类型)
- 需要保留原Vec:用
- 过滤逻辑:确保闭包中的类型匹配,通过解引用(
*或模式匹配)拿到需要比较的值。 - 收集结果:如果是引用迭代器,用
copied()/cloned()/map把引用转换成值,再用collect()生成新Vec。
比如针对你提到的实际场景(过滤Word对象),假设Word有一个id: i64字段,代码可以写成:
struct Word { id: i64, content: String, } fn main() { let target_id: i64 = 1; let words: Vec<Word> = vec![ Word { id: 1, content: "hello".into() }, Word { id: 2, content: "world".into() }, Word { id: 1, content: "rust".into() }, ]; // 保留原words的情况 let filtered_words: Vec<Word> = words .iter() .filter(|word| word.id == target_id) .cloned() // Word需要实现Clone trait .collect(); // 或者消耗原words的情况 let filtered_words: Vec<Word> = words .into_iter() .filter(|word| word.id == target_id) .collect(); }
内容的提问来源于stack exchange,提问作者Dolphin
相关产品推荐
相关产品推荐

