Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is "&&" being used in closure arguments?

I have two questions regarding this example:

let a = [1, 2, 3];

assert_eq!(a.iter().find(|&&x| x == 2), Some(&2));
assert_eq!(a.iter().find(|&&x| x == 5), None);
  1. Why is &&x used in the closure arguments rather than just x? I understand that & is passing a reference to an object, but what does using it twice mean?

    I don't understand what the documentation says:

    Because find() takes a reference, and many iterators iterate over references, this leads to a possibly confusing situation where the argument is a double reference. You can see this effect in the examples below, with &&x.

  2. Why is Some(&2) used rather than Some(2)?

like image 226
Sajuuk Avatar asked May 07 '17 05:05

Sajuuk


People also ask

Why is the sky blue short answer?

The Short Answer: Sunlight reaches Earth's atmosphere and is scattered in all directions by all the gases and particles in the air. Blue light is scattered more than the other colors because it travels as shorter, smaller waves. This is why we see a blue sky most of the time.

Why does the sky look blue?

The sky during the day During the day the sky looks blue because it's the blue light that gets scattered the most. It's redirected into many different directions all over the sky, whereas the other wavelengths aren't scattered as much.

What is the real colour of sky?

The sunlight reaching our eyes has a high ratio of short, bluish wavelengths compared to medium and long wavelengths, so we perceive the sky as being blue. Without an atmosphere the sky appears black, as evidenced by the lunar sky in pictures taken from the moon. But even a black sky has some lightness.

Why the sky is blue Class 10?

When a white light (from sun) enters the earth's atmosphere, it gets scattered away due to the atmospheric particles. Since, blue colour has the minimum wavelength, so blue colour scatters the most and thus the sky appears blue.


2 Answers

a is of type [i32; 3]; an array of three i32s. [i32; 3] does not implement an iter method, but it does dereference into &[i32]. &[i32] implements an iter method which produces an iterator. This iterator implements Iterator<Item=&i32>.

It uses &i32 rather than i32 because the iterator has to work on arrays of any type, and not all types can be safely copied. So rather than restrict itself to copyable types, it iterates over the elements by reference rather than by value.

find is a method defined for all Iterators. It lets you look at each element and return the one that matches the predicate. Problem: if the iterator produces non-copyable values, then passing the value into the predicate would make it impossible to return it from find. The value cannot be re-generated, since iterators are not (in general) rewindable or restartable. Thus, find has to pass the element to the predicate by-reference rather than by-value.

So, if you have an iterator that implements Iterator<Item=T>, then Iterator::find requires a predicate that takes a &T and returns a bool. [i32]::iter produces an iterator that implements Iterator<Item=&i32>. Thus, Iterator::find called on an array iterator requires a predicate that takes a &&i32. That is, it passes the predicate a pointer to a pointer to the element in question.

So if you were to write a.iter().find(|x| ..), the type of x would be &&i32. This cannot be directly compared to the literal i32 value 2. There are several ways of fixing this. One is to explicitly dereference x: a.iter().find(|x| **x == 2). The other is to use pattern matching to destructure the double reference: a.iter().find(|&&x| x == 2). These two approaches are, in this case, doing exactly the same thing. [1]

As for why Some(&2) is used: because a.iter() is an iterator over &i32, not an iterator of i32. If you look at the documentation for Iterator::find, you'll see that for Iterator<Item=T>, it returns an Option<T>. Hence, in this case, it returns an Option<&i32>, so that's what you need to compare it against.


[1]: The differences only matter when you're talking about non-Copy types. For example, |&&x| .. wouldn't work on a &&String, because you'd have to be able to move the String out from behind the reference, and that's not allowed. However, |x| **x .. would work, because that is just reaching inside the reference without moving anything.

like image 95
DK. Avatar answered Oct 21 '22 18:10

DK.


1) I thought the book explanation was good, maybe my example with .cloned() below will be useful. But since .iter() iterates over references, you have to specify reference additionally because find expects a reference.

2) .iter() is iterating over references; therefore, you find a reference.

You could use .cloned() to see what it would look like if you didn't have to do deal with references:

assert_eq!(a.iter().cloned().find(|&x| x == 2), Some(2));
like image 24
Akavall Avatar answered Oct 21 '22 20:10

Akavall