Nugget 18
Home|&x| vs |x|
You see .filter(|&x| x % 2 == 0) and .map(|x| x.parse())
side by side. Why does one have an & and the other doesn't?
The answer is in the layers of references.
let nums = vec![1, 2, 3, 4, 5]; // Why |&x| here? let evens = nums.iter().filter(|&x| x % 2 == 0); let text = "hello world"; // But |x| here? let words: Vec<&str> = text.split_whitespace().map(|x| x).collect();
Both are closures passed to iterator methods. Both get items and do something
with them. But one needs an extra & and the other doesn't.
Why?
filter and map DifferThe signatures tell the story:
// filter borrows each item — closure gets &Item
fn filter<P>(self, predicate: P) -> Filter<Self, P>
where
P: FnMut(&Self::Item) -> bool; // <-- NOTE: &Item
// map takes ownership of each item — closure gets Item
fn map<B, F>(self, f: F) -> Map<Self, F>
where
F: FnMut(Self::Item) -> B; // <-- NOTE: Item, not &Item
filter only looks at each item — it doesn't consume or
transform it. So it passes a reference (&Item).
map transforms and returns a new value, so it passes the item
by value (Item).
When you call nums.iter() on a Vec<i32>,
the iterator yields &i32. Then filter wraps
that in another reference:
vec![1, 2, 3]
.iter() // yields &i32 — Item = &i32
.filter(|x|) // x: &(&i32) — &Item = &&i32
// ^ ^^^^
// | filter adds one layer of &
// |
// Without pattern matching, you'd write:
// .filter(|x| **x % 2 == 0)
So the closure receives &&i32 — a reference to a reference.
That's two levels of indirection. The & in |&x|
is pattern matching that destructures one layer off.
These all do exactly the same thing:
let nums = vec![1, 2, 3, 4, 5]; // Style 1: Pattern matching — destructure one & let a: Vec<_> = nums.iter().filter(|&x| x % 2 == 0).collect(); // Style 2: Explicit dereference let b: Vec<_> = nums.iter().filter(|x| **x % 2 == 0).collect(); // Style 3: Double pattern — destructure both layers let c: Vec<_> = nums.iter().filter(|&&x| x % 2 == 0).collect(); assert_eq!(a, b); assert_eq!(b, c); // All three produce [2, 4]
| Style | Closure receives | What x is |
|---|---|---|
|&x| |
&&i32 |
&i32 (destructured one &) |
|x| **x |
&&i32 |
&&i32 (dereference manually) |
|&&x| |
&&i32 |
i32 (destructured both layers) |
map Doesn't Have This Problem
map receives Self::Item directly — no extra reference
layer. So the closure gets exactly what the iterator yields:
// split_whitespace() yields &str // map passes &str to the closure // So |x| gives you x: &str directly text.split_whitespace().map(|x| x.len()).collect(); // If you called .iter() on a Vec: // vec.iter() yields &i32 // map passes &i32 to the closure // So |x| gives you x: &i32 directly nums.iter().map(|x| x * 2).collect(); // x is &i32
No double-reference because map doesn't borrow — it consumes.
One less & layer.
The double-reference only happens when filter is called on an
iterator that already yields references (like .iter() on a
collection). Different iterator sources give different patterns:
// .iter() on Vec — yields &T → filter receives &&T let v = vec![1, 2, 3]; v.iter().filter(|&x| x % 2 == 0); // x: &i32 // .into_iter() on Vec — yields T → filter receives &T let v = vec![1, 2, 3]; v.into_iter().filter(|&x| x % 2 == 0); // x: i32 // Range — yields T directly → filter receives &T (1..=3).filter(|&x| x % 2 == 0); // x: i32 // chars() — yields char → filter receives &char "hello".chars().filter(|&c| c != 'l'); // c: char
The rule: filter always adds one layer of
&. So |&x| removes that one layer,
giving you the item the iterator yields.
filter borrows items — its closure receives &Item, always one reference layer extra.map consumes items — its closure receives Item directly.|&x| is pattern matching: "unwrap one layer of & from what I receive.".iter() on Vec<T> meets filter, the closure gets &&T.|&x|, |x| **x, and |&&x| x are three equivalent ways to reach the same value.