Thanks to @user#0540 and @Globi#0117 on the #beginners discord
Question:
Coming from JS/C#/Haskell and trying to understand the &
and *
a bit better. In this code snippet, the n
in the lambda apparently can either be |&n| n%2==0
or |n| *n%2==0
. Could some one explain this a bit better? I think its something to do with reference/defreferece, but still not comfortable with those ideas.
let arr: [u16; 5] = [1, 2, 3, 4, 5];
let mut iterator = arr.iter().filter(|&n| n%2==0);
&n
"pattern matches on a reference". Its almost as if:
newtype &a = &{ * :: a }
Thats not valid haskell but its roughly how ref/derefs behave here
@gb: hmmm, so the ref is kind of like a wrapper/alias that has no runtime impact? not sure I'm following the &{ * :: a }.
@user Imagine you had
newtype Box a = Box { unBox :: a }
-- and
\(Box n) -> n `mod` 2 == 0
-- and
\box -> unBox box `mod` 2 == 0
-- are the same
@globi:
|n: &u16| ...
|&n: u16| ...
@gregberns: Can you explain a bit about the purpose of the ref stuff? Is that so values dont have to be passed?
@user: Yeah, e.g. if you had HugeDataStructure that contained 50 integers or something. Passing &HugeDataStructure just passes on the address of a HugeDataStructure. Which can be a lot more efficient.
@globi: Also your simple example might be a tiny bit more complicated than it seems: arr.iter() implements Iterator<Item = &u16>, that's already an iterator over a reference but filter then takes a closure that takes the iterator's item by reference again so if you try to annotate n in your closure, you'll see it's actually a &&u16 you only need to dereference it once (to get an &u16) because there is an implementation of % for &u16 and u16 to illustrate, here are 5 equivalents way of writing your filter: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=28031705a4539b0570a5f81c7d233dd1
fn main() {
let arr: [u16; 5] = [1, 2, 3, 4, 5];
let evens = arr.iter().filter(|n| **n%2==0);
let evens = arr.iter().filter(|n| *n%2==0); // works with &u16 % u16
let evens = arr.iter().filter(|&n| *n%2==0);
let evens = arr.iter().filter(|&n| n%2==0); // works with &u16 % u16
let evens = arr.iter().filter(|&&n| n%2==0);
}