Reference 为什么find闭包的参数需要两个符号?
我一直在玩Rust by to it——基于我在OCaml中的功能风格实现。我特别想看看Rust如何处理函数式代码 最终的结果是:它可以工作,而且速度非常快——比OCaml快得多。它几乎触及了命令式C/C++的速度,这真的很酷 不过,有一件事让我很困扰——为什么我在代码的最后一行需要两个符号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
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
,它将一个谓词作为参数,该谓词将项作为参数。SiceItem
在您的案例中已经是一个引用,谓词必须采用&&(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