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.
The error message
Section titled “The error message”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.
What it means
Section titled “What it means”The two note lines are the heart of the message. Read them as “the method wanted this, you wrote that”:
- expected
fn(&{integer}) -> _:mapwill 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 ani32by 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.
Why Rust does this
Section titled “Why Rust does this”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 aVecyou own) gives each item away:T.filterandfindlend you the item again, so on top of.iter()you get&&T.sort_bylends you two items:&Tand&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.
How to fix it
Section titled “How to fix it”Fix 1: Remove the type annotation
Section titled “Fix 1: Remove the type annotation”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]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]Notice the difference: |p: &i32| means “p is a reference”, while |&p| means “I receive a reference, give me what’s behind it”.
Fix 3: Change what the iterator hands out
Section titled “Fix 3: Change what the iterator hands out”Choose this when you really do want the values, not references. Two ways to get them:
.iter().copied()turns every&i32into ani32. Use it for smallCopytypes like numbers,charandbool. (.cloned()does the same for types likeString, by cloning.).into_iter()on aVechands out the items themselves. TheVecis 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"]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 morefn 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"]More on &str versus String in Strings.
Where you’ll usually see it
Section titled “Where you’ll usually see it”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|.
Related errors
Section titled “Related errors”- E0593: closure takes the wrong number of arguments: the sister error, for the count of parameters (for example
|a, b|where one tuple is passed). - E0057: closure called with the wrong number of arguments: you call a closure yourself and pass too few or too many values.
- E0308: mismatched types: the general “wrong type” error, for example when the closure’s return value has the wrong type, or for a
fn(...)pointer parameter. - E0599: no method found: the
collectorsum“trait bounds were not satisfied” error that follows E0631. It goes away with E0631. - E0507: cannot move out of a borrowed value: when you try to take ownership of items you only borrowed with
.iter(). - All compiler errors: the full list of error pages.
Quick check
Section titled “Quick check”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
Read more
Section titled “Read more”- E0631 — Rust error codes index: the official explanation of this error.
- Processing a Series of Items with Iterators — The Rust Book:
iter,into_iteranditer_mut, and what each one hands out. - Closures — The Rust Book: how closure parameter types are inferred, and when to write them yourself.
Iterator::copied— standard library docs: turn an iterator of&Tinto an iterator ofT.slice::sort_by— standard library docs: the signature that shows the comparison closure receives two references.