我解决了一个codewars的数据,其中一个告诉
您在这个类型中的目标是实现一个差分函数,它从一个列表减去另一个列表并返回结果。
这里有两个实现。其中一种需要克隆特性,另一种不需要。为什么第二个(最短的解决方案)不需要克隆特性?
:
fn array_diff<T: PartialEq + Clone>(a: Vec<T>, b: Vec<T>) -> Vec<T> {
let mut res: Vec<T> = Vec::new();
for av in a.iter() {
let mut found = false;
for bv in b.iter() {
if *av == *bv {
found = true;
break;
}
}
if !found {
res.push(av.clone());
}
}
return res;
}
和第二
fn array_diff<T: PartialEq>(a: Vec<T>, b: Vec<T>) -> Vec<T> {
a.into_iter().filter(|x| !b.contains(x)).collect()
}
在第二个示例中,a.into_iter()
使用a
中的值,然后在返回的Vec中收集它们作为拥有的值。
在第一个示例中,值没有被使用。相反,它们是克隆的(所以需要Clone特性)。
您可以通过以相同的方式使用a
来获得与第一个版本相同的需求:
// Get rid of Clone requirement
fn array_diff<T: PartialEq>(a: Vec<T>, b: Vec<T>) -> Vec<T> {
let mut res: Vec<T> = Vec::new();
for av in a { // <--- remove the `.iter()`. Now `av` is owned.
let mut found = false;
for bv in b.iter() { // <-- Can't consume b; it's searched multiple times
if av == *bv { // <-- No `*` on the av because it's owned.
found = true;
break;
}
}
if !found {
res.push(av); // <-- push the owned value, not a clone
}
}
return res;
}
for
循环隐式调用.into_iter()
(这就是for
循环的工作方式)。
iter()
按照约定创建了一个不可变的借用Iterator。
注意,这两个函数都拥有自己的参数,这对于一个不同的函数来说有点奇怪。另一种构建方法是将Clone需求应用于第二个示例,并传递引用而不是拥有的值(这是我首选的解决方案,因为它可能是最简单的使用方法):
fn array_diff<T: PartialEq + Clone>(a: &[T], b: &[T]) -> Vec<T> {
a.iter()
.filter(|x| !b.contains(x))
.cloned()
.collect()
}
(关于从Vec
到[]
的切换,参见下面Cerberus的注释)
或者结果可以是对第一个片(iter()
而不是iter_into()
)的引用,以避免任何复制,但是现在您需要担心a
的生命周期,这会使使用变得更加复杂:
fn array_diff<'a, T: PartialEq>(a: &'a [T], b: &[T]) -> Vec<&'a T> {
a.iter().filter(|x| !b.contains(x)).collect()
}