通过将我的Score4 AI引擎移植到它,我一直在玩Rust - 基于我在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) {
...
Run Code Online (Sandbox Code Playgroud)
我添加它们是因为编译错误"引导"了我; 但我试图理解为什么......我使用Stack Overflow中其他地方提到的技巧来"询问"编译器告诉我什么类型的东西:
let moves_and_scores: Vec<_> = moves_and_boards
.iter()
.map(|&(column,board)| (column, score_board(&board)))
.collect();
let () = moves_and_scores;
Run Code Online (Sandbox Code Playgroud)
...导致此错误:
src/main.rs:108:9: 108:11 error: mismatched types:
expected `collections::vec::Vec<(u32, i32)>`,
found `()`
(expected struct `collections::vec::Vec`,
found ()) [E0308]
src/main.rs:108 let () = moves_and_scores;
Run Code Online (Sandbox Code Playgroud)
......正如我所料,moves_and_scores是一个元组的向量:Vec<(u32, i32)>.但随后,在不久的下一行,iter()并find()强迫我用可怕的双&符号在封闭参数:
if let Some(killer_move) = moves_and_scores.iter()
.find(|& &(_,score)| score==target_score) {
Run Code Online (Sandbox Code Playgroud)
为什么find闭合需要两个&符号?我可以看到为什么它可能需要一个(通过引用传递元组以节省时间/空间),但为什么两个?是因为iter?也就是说,是iter创建引用,然后find期望每个输入的引用,所以引用的引用?
如果是这样的话,这可能是Rust中一个相当难看的设计缺陷吗?
实际上,我希望find并且map所有其他功能原语都是集合本身的一部分.迫使我iter()去做任何类型的功能式工作似乎很麻烦,如果它在每个可能的功能链中强制使用这种"双符号",那就更是如此.
我希望我遗漏了一些明显的东西 - 任何帮助/澄清都是最受欢迎的.
sel*_*tze 14
这里
moves_and_scores.iter()
Run Code Online (Sandbox Code Playgroud)
给你一个借来的向量元素的迭代器.如果按照API文档是什么类型,这是,你会发现它只是借来的片迭代器,这实现了Iterator与Item=&T地方T是(u32, i32)在你的案件.
然后,您使用find带有&Itemas参数的谓词.Item在你的情况下,Sice 已经是一个参考,谓词必须采用&&(u32, i32).
pub trait Iterator {
...
fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
where P: FnMut(&Self::Item) -> bool {...}
... ^
Run Code Online (Sandbox Code Playgroud)
它可能是这样定义这个,因为它应该只是一个检查项目,并返回一个布尔值.这不需要按值传递项目.
如果你想要一个迭代器,(u32, i32)你可以写
moves_and_scores.iter().cloned()
Run Code Online (Sandbox Code Playgroud)
cloned()从一个迭代转换用Item类型&T的一个与Item类型T,如果T是Clone.另一种方法是使用into_iter()而不是iter().
moves_and_scores.into_iter()
Run Code Online (Sandbox Code Playgroud)
两者之间的区别在于第一个选项克隆借来的元素,而第二个选项使用向量并将元素移出它.
通过写这样的lambda
|&&(_, score)| score == target_score
Run Code Online (Sandbox Code Playgroud)
你解构"双引用"并创建一个本地副本i32.这是允许的,因为它i32是一种简单的类型Copy.
您也可以编写,而不是解构谓词的参数
|move_and_score| move_and_score.1 == target_score
Run Code Online (Sandbox Code Playgroud)
因为点运算符会根据需要自动解除引用次数.