在使用.filter()之前还是之后应该使用.cloned()?

4

假设我有一个向量,我只想保留其中的偶数元素。我需要使用 cloned()filter()。例如:

fn main() {
    let my_vec: Vec<i32> = vec![1,2,3,4];

    let my_vec_1: Vec<i32> = my_vec.iter().cloned().filter(|&x| x % 2 == 0).collect();
    println!("{:?}", my_vec_1);

    let my_vec_2: Vec<i32> = my_vec.iter().filter(|&x| x % 2 == 0).cloned().collect();
    println!("{:?}", my_vec_2);

}

两种方法都可以。在使用filter()之后使用cloned()似乎更有效一些,因为我不必将迭代器的所有元素从&T转换为T,只需要过滤掉的那些元素。在我的例子中,这是一半的元素。
然而,我似乎看到filter()之前应用了cloned()。这里有一个例子:method.inspect 我认为也许对于没有实现Copy特性的类型,必须在.cloned()之前使用,但这似乎不是这种情况:嵌套向量示例。此外,由于filter使用FnMut(&Self::Item),我认为这不应该是一个问题。
filter()之前使用cloned()是否有优势?这更多地是一个风格问题吗?如果是的话,有喜欢的风格吗?
2个回答

7

这是对Matthieu M.的回答的一种替代方案。

当你有小的Copy元素时,应该尽快进行Clone。在这些情况下,克隆几乎总是免费的,但我曾经看到过额外的间接操作让优化器混淆。当你在整数容器上调用iter时,cloned几乎总是紧随其后,除非你可以将其合并到下一个调用中,例如通过调用map时的额外解引用。

因此,在给定的情况下,尽早使用cloned是完全合理的。这确实是一种微小的优化,但往往很容易做,并且通常使类型更容易处理,因此我认为这样做没有任何不利影响。

在未来,copied可能会成为处理这个问题的首选方式。


当使用非Copy类型时,其中Clone可能不那么便宜,延迟克隆是一个更好的默认值。


1
我不同意,clone 应该始终被视为“不便宜”,编译器应该尽其职责并优化“无用的引用”。如果你把 cloned() 放在后面,即使你改变了代码,你仍然会做“正确的事情”,但如果你把它放在前面,你就需要记得把 cloned() 移到后面。 - Stargateur
1
如果你在需要强制类型实现拷贝的地方使用copied(),我会同意。 - Stargateur
@Stargateur 我已经添加了一条注释。 - Veedrac

6

这不是样式的问题。

inspect的示例旨在展示inspect,仅此而已。它以一种可能有些愚蠢的方式使用了.cloned,但选择cloned可能是因为其易于理解的语义,从而创建一个易于理解的“复杂迭代器序列”。


那么,在.filter(...)之前还是之后加上.cloned()?正如您所提到的,除非克隆对过滤必要(这会让人感到惊讶),否则经验法则是在之后克隆,以最小化克隆元素的数量。

这里没有样式,只是实用性能评估。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接