Reference 为什么find闭包的参数需要两个符号?

Reference 为什么find闭包的参数需要两个符号?,reference,rust,Reference,Rust,我一直在玩Rust by to it——基于我在OCaml中的功能风格实现。我特别想看看Rust如何处理函数式代码 最终的结果是:它可以工作,而且速度非常快——比OCaml快得多。它几乎触及了命令式C/C++的速度,这真的很酷 不过,有一件事让我很困扰——为什么我在代码的最后一行需要两个符号 let moves_and_scores: Vec<_> = moves_and_boards .iter() .map(|&(column,board)| (colum

我一直在玩Rust by to it——基于我在OCaml中的功能风格实现。我特别想看看Rust如何处理函数式代码

最终的结果是:它可以工作,而且速度非常快——比OCaml快得多。它几乎触及了命令式C/C++的速度,这真的很酷

不过,有一件事让我很困扰——为什么我在代码的最后一行需要两个符号

let moves_and_scores: Vec<_> = moves_and_boards
    .iter()
    .map(|&(column,board)| (column, score_board(&board)))
    .collect();
let target_score = if maximize_or_minimize { 
    ORANGE_WINS 
} else { 
    YELLOW_WINS 
};
if let Some(killer_move) = moves_and_scores.iter()
    .find(|& &(_,score)| score==target_score) {
         ...
为什么
find
闭包需要两个符号?我可以理解为什么它可能需要一个(通过引用传递元组以节省时间/空间),但为什么需要两个?是因为国际热核实验堆吗?也就是说,
iter
是否创建了引用,然后
find
希望在每个输入上都有一个引用,那么在一个引用上有一个引用呢

如果是这样的话,这难道不是铁锈中一个相当丑陋的设计缺陷吗

事实上,我希望
find
map
以及所有其他函数原语都是集合本身的一部分。强迫我去
iter()
做任何类型的函数式工作似乎都很麻烦,如果它在每一个可能的函数链中都强制使用这种“双安培数”,那就更麻烦了

我希望我错过了一些显而易见的东西-欢迎提供任何帮助/澄清。

这里

moves_and_scores.iter()
为您提供对借用的向量元素的迭代器。如果您按照API文档了解这是什么类型,您会注意到它只是一个借来的片段的迭代器,它使用
Item=&T
实现
iterator
,其中
T
(u32,i32)

然后,使用
find
,它将一个谓词作为参数,该谓词将
项作为参数。Sice
Item
在您的案例中已经是一个引用,谓词必须采用
&&(u32,i32)

Clone()
如果
T
Clone
,则将迭代器从带有
项的迭代器转换为带有
项的迭代器。另一种方法是在iter()中使用
而不是
iter()

两者之间的区别在于,第一个选项克隆借用的元素,而第二个选项使用向量并将元素移出向量

通过这样写lambda

|&&(_, score)| score == target_score
您可以分解“双重引用”并创建
i32
的本地副本。这是允许的,因为
i32
是一种简单的类型,即
Copy

您还可以编写

|move_and_score| move_and_score.1 == target_score

因为点运算符会根据需要自动取消引用任意次数。

祝贺您管理了该端口,在函数样式代码方面击败了OCaml,这意味着您做得对@马蒂厄姆。谢谢我希望有一种更干净的方法来处理函数链(即
.iter().map(…).iter().filter()…iter().find(…)
),而不在每一步引入额外的参考级别-但似乎我无法避免。感谢您的反馈!
iter().cloned()
对性能有影响吗?我是说,它真的分配“克隆人”吗?另外,我相信
进入iter()
肯定会对性能产生影响,因为它的移动语义会改变源向量。我认为最好的是你的第三个建议-使用“自动取消引用,需要多少次”-必须仔细阅读。顺便说一句,关于Rust为什么选择不将函数运算符(映射、过滤器等)作为集合的一部分,并且需要先使用
.iter()
(这引入了额外级别的“引用间接寻址”的想法在每一步)…@ttsiodras关于性能:所有这些都不应该真正重要。克隆
(u32,i32)
类型的元组非常便宜。不要让“克隆人”这个词吓到你。:-)对于simpe“纯旧数据类型”,克隆和复制基本相同。但有些类型无法复制,因为它们更复杂。只有在这种情况下,我才会担心克隆。@ttsiodra有许多不同的方法可以迭代一个集合(
iter
iter\u mut
到iter
drain
)。每种方法都有各自的用途,但实际上并没有一种“正确”的方法来做到这一点。我想,这就是为什么你必须明确的原因。在软件工程中,生锈是一种奇妙的经历
moves_and_scores.iter()
pub trait Iterator {
    ...
    fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
    where P: FnMut(&Self::Item) -> bool {...}
    ...            ^
moves_and_scores.iter().cloned()
moves_and_scores.into_iter()
|&&(_, score)| score == target_score
|move_and_score| move_and_score.1 == target_score