Skip to content

Rust Error E0631: Type Mismatch in Closure Arguments

E0631 means your closure has the right number of parameters, but at least one has the wrong type. Nine times out of ten, the difference is a single &: you wrote |x: i32|, but the iterator lends you &i32. The quickest fix is often to delete the type annotation and let Rust work it out. This page shows that fix first, then explains where the & comes from, so you can predict it next time. For the other errors in this series, see Rust compiler errors.

error[E0631]: type mismatch in closure arguments
--> src/main.rs:3:43
|
3 | let doubled: Vec<i32> = prices.iter().map(|p: i32| p * 2).collect(); // ❌ items are &i32
| ^^^ -------- found signature defined here
| |
| expected due to this
|
= note: expected closure signature `fn(&{integer}) -> _`
found closure signature `fn(i32) -> _`
note: required by a bound in `map`
help: consider adjusting the signature so it borrows its argument
|
3 | let doubled: Vec<i32> = prices.iter().map(|p: &i32| p * 2).collect(); // ❌ items are &i32
| +

This is the program that produces it:

fn main() {
let prices = vec![120, 45, 300];
let doubled: Vec<i32> = prices.iter().map(|p: i32| p * 2).collect(); // ❌ items are &i32
println!("{:?}", doubled);
}

rustc also prints a second, longer error right after it: the method `collect` exists for struct `Map<...>`, but its trait bounds were not satisfied (E0599). That one is only a side effect. Fix E0631 and it disappears.

The two note lines are the heart of the message. Read them as “the method wanted this, you wrote that”:

  • expected fn(&{integer}) -> _: map will call your closure with a reference to an integer. {integer} means “some integer type Rust hasn’t pinned down yet”, and _ means “any return type”.
  • found fn(i32) -> _: your closure says it takes an i32 by value.

Put them side by side and the only difference is the &. The help: line shows the one-character fix.

Think of a coat check. You hand over your coat and get a ticket back. .iter() works the same way: it doesn’t hand you the items, it hands you tickets to them (references). A closure that insists on the coat itself won’t accept a ticket.

Every iterator method decides exactly what type it passes to your closure, and that type depends on how you made the iterator:

  • v.iter() lends each item: &T.
  • v.into_iter() (on a Vec you own) gives each item away: T.
  • filter and find lend you the item again, so on top of .iter() you get &&T.
  • sort_by lends you two items: &T and &T.

When you leave the parameter types out, Rust fills them in from the method, so they always fit. When you write a type yourself, Rust takes you at your word and checks it. It won’t quietly copy the value or turn a reference into an owned value, because that would change what your code does (and for a String, a copy costs memory and time). The Iterators lesson shows the three ways to get an iterator, and Borrowing explains references.

Choose this first. Closure parameters almost never need a type: Rust knows exactly what map, filter and sort_by pass. Delete : i32 and the code compiles:

fn main() {
let prices = vec![120, 45, 300];
let ages = vec![12, 34, 17, 50];
let mut scores = vec![42, 7, 99, 15];
// no type annotations: Rust uses what the iterator really gives
let doubled: Vec<i32> = prices.iter().map(|p| p * 2).collect();
let adults: Vec<&i32> = ages.iter().filter(|age| **age >= 18).collect();
scores.sort_by(|a, b| b.cmp(a));
println!("{:?}", doubled);
println!("{:?}", adults);
println!("{:?}", scores);
}

Output:

[240, 90, 600]
[34, 50]
[99, 42, 15, 7]
▶ Try it Yourself

p * 2 works on a &i32 because Rust’s number operators accept references too. In filter, age is a &&i32, so **age follows both references to reach the number. Comparisons like b.cmp(a) work on references directly.

Fix 2: Write the type the method really passes

Section titled “Fix 2: Write the type the method really passes”

Choose this when you want to keep the type visible, for example to make a long chain easier to read. Follow rustc’s help: and add the &. You can also put the & in the pattern: |&p| takes the reference apart and gives you a plain copy of the number (this works for Copy types like integers):

fn main() {
let prices = vec![120, 45, 300];
let ages = vec![12, 34, 17, 50];
let mut scores = vec![42, 7, 99, 15];
// write the real types: & for .iter(), && inside filter
let doubled: Vec<i32> = prices.iter().map(|p: &i32| p * 2).collect();
let adults: Vec<&i32> = ages.iter().filter(|age: &&i32| **age >= 18).collect();
scores.sort_by(|a: &i32, b: &i32| b.cmp(a));
// or copy the number out with a & pattern
let tax: Vec<i32> = prices.iter().map(|&p| p / 10).collect();
println!("{:?}", doubled);
println!("{:?}", adults);
println!("{:?}", scores);
println!("{:?}", tax);
}

Output:

[240, 90, 600]
[34, 50]
[99, 42, 15, 7]
[12, 4, 30]
▶ Try it Yourself

Notice the difference: |p: &i32| means “p is a reference”, while |&p| means “I receive a reference, give me what’s behind it”.

Choose this when you really do want the values, not references. Two ways to get them:

  • .iter().copied() turns every &i32 into an i32. Use it for small Copy types like numbers, char and bool. (.cloned() does the same for types like String, by cloning.)
  • .into_iter() on a Vec hands out the items themselves. The Vec is used up afterwards, so choose this when you don’t need it any more.
fn main() {
let prices = vec![120, 45, 300];
// .copied() turns &i32 items into i32 items
let doubled: Vec<i32> = prices.iter().copied().map(|p: i32| p * 2).collect();
println!("{:?}", doubled);
// .into_iter() on a Vec hands out the items themselves (and uses up the Vec)
let names = vec![String::from("ferris"), String::from("corro")];
let loud: Vec<String> = names.into_iter().map(|name: String| name.to_uppercase()).collect();
println!("{:?}", loud);
}

Output:

[240, 90, 600]
["FERRIS", "CORRO"]
▶ Try it Yourself

If you still need names after the loop, keep .iter() and take &String instead. Moving out of a Vec you only borrowed is a different error, E0507.

Fix 4: Make a named function take what the iterator gives

Section titled “Fix 4: Make a named function take what the iterator gives”

Choose this when you pass a function by name, like .map(shout). The message then says “function” instead of “closure”:

error[E0631]: type mismatch in function arguments
--> src/main.rs:7:51
|
1 | fn shout(word: &String) -> String {
| --------------------------------- found signature defined here
...
7 | let loud: Vec<String> = words.into_iter().map(shout).collect();
| --- ^^^^^ expected due to this
| |
| required by a bound introduced by this call
|
= note: expected function signature `fn(&str) -> _`
found function signature `fn(&String) -> _`

The items are &str, but shout wants &String. A good habit: let functions that only read text take &str. Then they accept string literals, &String and more. When the iterator adds an extra & (like filter does), wrap the call in a short closure. Inside a normal function call, Rust removes extra &s for you (this is called deref coercion), but it can’t do that when you pass the function by name:

// take &str: works for string literals, &String and more
fn shout(word: &str) -> String {
word.to_uppercase()
}
fn is_long(word: &str) -> bool {
word.len() > 4
}
fn main() {
let words = vec!["crab", "rustacean", "ferris"];
// the items are &str, so shout can be passed by name
let loud: Vec<String> = words.iter().copied().map(shout).collect();
println!("{:?}", loud);
// filter gives &&str: a small closure lets Rust convert it for you
let long: Vec<&str> = words.iter().copied().filter(|w| is_long(w)).collect();
println!("{:?}", long);
}

Output:

["CRAB", "RUSTACEAN", "FERRIS"]
["rustacean", "ferris"]
▶ Try it Yourself

More on &str versus String in Strings.

Sorting with typed parameters. scores.sort_by(|a: i32, b: i32| b.cmp(&a)) gives E0631 with expected closure signature `for<'a, 'b> fn(&'a {integer}, &'b {integer}) -> _`. The for<'a, 'b> part only says “for any borrow”. Fix: |a, b| b.cmp(a). See Sorting.

Map entries with owned types. stock.iter().map(|(name, count): (String, i32)| ...) on a HashMap<String, i32> gives expected closure signature `fn((&String, &_)) -> _`. .iter() on a map lends both the key and the value. Fix: drop the annotation, or write (&String, &i32).

Your own generic function. If fn apply<F: Fn(i32) -> i32>(f: F, x: i32) gets a closure |x: f64| x / 2.0, rustc reports expected closure signature `fn(i32) -> _` and found closure signature `fn(f64) -> _`, pointing at the bound. Fix: make the closure take i32 (and convert inside, x as f64 / 2.0), or change the bound if f64 is what you meant. See Closure traits.

for_each with String. words.iter().for_each(|w: String| ...) on a Vec<&str> expects fn(&&str). A &str is not a String. Fix: |w|, or |w: &&str|.

Quick check

1. let v = vec![1, 2, 3]; What type does the closure in v.iter().map(|x| ...) receive?

2. The note says expected closure signature fn(&{integer}) -> _, found closure signature fn(i32) -> _. What is the quickest fix?

3. What does |&p| p * 2 do inside prices.iter().map(...)?

Score: 0 / 3