为什么 find 闭包的参数需要两个 & 符号? [英] Why does the argument for the find closure need two ampersands?

查看:19
本文介绍了为什么 find 闭包的参数需要两个 & 符号?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在通过移植我的 Score4 AI 引擎来玩 Rust- 基于我在 OCaml 中的函数式实现的工作.我特别想看看 Rust 如何使用函数式代码.

I have been playing with Rust by porting my Score4 AI engine to it - basing the work on my functional-style implementation in OCaml. I specifically wanted to see how Rust fares with functional-style code.

最终结果:它有效,而且速度非常快 - 比 OCaml 快得多.它几乎可以达到命令式 C/C++ 的速度——这真的很酷.

The end result: It works, and it's very fast - much faster than OCaml. It almost touches the speed of imperative-style C/C++ - which is really cool.

不过,有一点让我感到困扰——为什么我在这段代码的最后一行需要两个 & 符号?

There's a thing that troubles me, though — why do I need two ampersands in the last line of this code?

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) {
         ...

我添加它们是因为编译器错误引导"了我;但我试图理解为什么......我使用了 Stack Overflow 中其他地方提到的技巧来询问"编译器告诉我某物是什么类型:

I added them is because the compiler errors "guided" me to it; but I am trying to understand why... I used the trick mentioned elsewhere in Stack Overflow to "ask" the compiler to tell me what type something is:

let moves_and_scores: Vec<_> = moves_and_boards
    .iter()
    .map(|&(column,board)| (column, score_board(&board)))
    .collect();
let () = moves_and_scores;

...导致此错误的原因:

...which caused this error:

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;

...正如我所料,moves_and_scores 是一个元组向量:Vec<(u32, i32)>.但是,在紧接的下一行中,iter()find() 迫使我在闭包参数中使用可怕的双符号:

...as I expected, moves_and_scores is a vector of tuples: Vec<(u32, i32)>. But then, in the immediate next line, iter() and find() force me to use the hideous double ampersands in the closure parameter:

if let Some(killer_move) = moves_and_scores.iter()
    .find(|& &(_,score)| score==target_score) {

为什么 find 闭包需要两个 & 符号?我可以理解为什么它可能需要一个(通过引用传递元组以节省时间/空间)但为什么需要两个?是不是因为iter?也就是说,是 iter 创建引用,然后 find 期望在每个输入上有一个引用,所以在一个引用上有一个引用?

Why does the find closure need two ampersands? I could see why it may need one (pass the tuple by reference to save time/space) but why two? Is it because of the iter? That is, is the iter creating references, and then find expects a reference on each input, so a reference on a reference?

如果是这样,这难道不是 Rust 中相当丑陋的设计缺陷吗?

If this is so, isn't this, arguably, a rather ugly design flaw in Rust?

事实上,我希望 findmap 以及所有其余的功能原语成为集合本身的一部分.强迫我使用 iter() 来做任何类型的函数式工作似乎很繁重,如果它在每个可能的函数链中强制使用这种双 & 号",则更是如此.

In fact, I would expect find and map and all the rest of the functional primitives to be parts of the collections themselves. Forcing me to iter() to do any kind of functional-style work seems burdensome, and even more so if it forces this kind of "double ampersands" in every possible functional chain.

我希望我遗漏了一些明显的东西 - 非常欢迎任何帮助/澄清.

I am hoping I am missing something obvious - any help/clarification most welcome.

推荐答案

这里

moves_and_scores.iter()

为您提供了一个对 借用 向量元素的迭代器.如果您遵循 API 文档这是什么类型,您会注意到它只是借用切片的迭代器,并且它使用 Item=&T 实现了 Iterator 其中 T 在您的情况下是 (u32, i32).

gives you an iterator over borrowed vector elements. If you follow the API doc what type this is, you'll notice that it's just the iterator for a borrowed slice and this implements Iterator with Item=&T where T is (u32, i32) in your case.

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

Then, you use find which takes a predicate which takes a &Item as parameter. Sice Item already is a reference in your case, the predicate has to take a &&(u32, i32).

pub trait Iterator {
    ...
    fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
    where P: FnMut(&Self::Item) -> bool {...}
    ...            ^

它可能被定义为 this 因为它只应该检查项目并返回一个布尔值.这不需要按值传递项目.

It was probably defined like this because it's only supposed to inspect the item and return a bool. This does not require the item being passed by value.

如果你想要一个迭代器 (u32, i32) 你可以写

If you want an iterator over (u32, i32) you could write

moves_and_scores.iter().cloned()

cloned() 将迭代器从具有 Item 类型 &T 的迭代器转换为具有 Item 类型的迭代器> 如果 TClone,则输入 T.另一种方法是使用 into_iter() 而不是 iter().

cloned() converts the iterator from one with an Item type &T to one with an Item type T if T is Clone. Another way to do it would be to use into_iter() instead of iter().

moves_and_scores.into_iter()

两者的区别在于第一个选项克隆借用的元素,而第二个选项消耗向量并将元素移出其中.

The difference between the two is that the first option clones the borrowed elements while the 2nd one consumes the vector and moves the elements out of it.

像这样写 lambda

By writing the lambda like this

|&&(_, score)| score == target_score

您解构双重引用"并创建i32 的本地副本.这是允许的,因为 i32 是一个简单的类型,即 Copy.

you destructure the "double reference" and create a local copy of the i32. This is allowed since i32 is a simple type that is Copy.

除了解构你的谓词的参数,你也可以写

Instead of destructuring the parameter of your predicate you could also write

|move_and_score| move_and_score.1 == target_score

因为点运算符会根据需要自动取消引用多次.

because the dot operator automatically dereferences as many times as needed.

这篇关于为什么 find 闭包的参数需要两个 & 符号?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆