Erro E0057 do Rust: this function takes N arguments but M were supplied (closures)
O E0057 quer dizer que você chamou uma closure (função anônima) com o número errado de argumentos: de menos ou de mais. É a versão para closures do E0061, e a mensagem é quase igual. A correção costuma ser rápida: olhe o |...| da closure e passe um valor para cada parâmetro. Esta página também fala de dois parentes próximos que você vai encontrar com iteradores, o E0593 e o E0631, porque eles vêm da mesma confusão. Para os outros erros desta série, veja Erros do compilador Rust.
A mensagem de erro
Seção intitulada “A mensagem de erro”error[E0057]: this function takes 2 arguments but 1 argument was supplied --> src/main.rs:3:17 |3 | let total = add(1); // ❌ add quer dois números | ^^^--- argument #2 of type `i32` is missing |note: closure defined here --> src/main.rs:2:15 |2 | let add = |a: i32, b: i32| a + b; | ^^^^^^^^^^^^^^^^help: provide the argument |3 | let total = add(1, /* i32 */); // ❌ add quer dois números | +++++++++++Em português: “esta função recebe 2 argumentos, mas foi passado 1”. O rótulo diz que falta o argumento nº 2, do tipo i32, e a nota aponta para onde a closure foi definida.
Este é o programa que causa o erro:
fn main() { let add = |a: i32, b: i32| a + b; let total = add(1); // ❌ add quer dois números println!("{total}");}Argumentos de mais dão o mesmo código, com um rótulo “unexpected argument” (argumento inesperado) e uma ajuda “remove the extra argument” (remova o argumento extra):
error[E0057]: this function takes 1 argument but 2 arguments were supplied --> src/main.rs:3:5 |3 | greet("Ferris", "Corro"); | ^^^^^ ------- unexpected argument #2 of type `&'static str` |note: closure defined hereO que significa
Seção intitulada “O que significa”Leia a mensagem como a de funções: a primeira linha conta (a closure recebe 2, você passou 1), o rótulo embaixo da sua chamada diz qual argumento falta ou sobra, e o help: mostra onde ele entra. /* i32 */ é só um comentário que serve de lugar reservado e diz o tipo. Coloque um valor de verdade ali.
E0057 ou E0061? A primeira linha é a mesma. É o note: que diferencia:
closure defined here: você chamou uma closure. Isso é o E0057.callable defined here: você chamou umfgenérico com um bound comoF: Fn(i32). Também é o E0057.function defined here: umafnnormal, um método ou um ponteiro de função (let f: fn(i32, i32) -> i32 = add;). Isso é o E0061.
De qualquer jeito, a correção é a mesma: faça a chamada bater com a lista de parâmetros.
Por que o Rust faz isso
Seção intitulada “Por que o Rust faz isso”A lista de parâmetros de uma closure é tão fixa quanto a de uma função. |a: i32, b: i32| recebe exatamente dois i32, todas as vezes. Não existem argumentos com valor padrão nem “passe menos se quiser”. Mesmo quando você não escreve os tipos, o rustc os descobre pelo corpo da closure e pelo primeiro uso, e a partir daí eles ficam travados.
Por baixo dos panos, uma closure implementa uma das traits Fn com uma lista fixa de tipos de argumento, como Fn(i32, i32) -> i32. O compilador confere cada chamada com essa lista, então uma chamada com a quantidade errada nunca chega ao seu programa rodando. Como as closures e os seus parâmetros funcionam está em Closures e em Traits de closures.
Como corrigir
Seção intitulada “Como corrigir”Correção 1: Faça a chamada bater com os parâmetros da closure
Seção intitulada “Correção 1: Faça a chamada bater com os parâmetros da closure”Escolha esta quase sempre. Vá até o local do note:, conte os parâmetros entre as barras |...| e passe um valor para cada um. Se você tem mais valores do que parâmetros, chame a closure mais de uma vez:
fn main() { let add = |a: i32, b: i32| a + b; let greet = |name: &str| println!("Olá, {name}!");
let total = add(1, 2); println!("{total}");
greet("Ferris"); greet("Corro"); // uma chamada por nome}Saída:
3Olá, Ferris!Olá, Corro!Se a closure realmente deveria receber outra quantidade de valores, mude a closure. Também não tem problema, desde que todas as chamadas concordem com ela.
Correção 2: Tuplas: uma tupla é um argumento
Seção intitulada “Correção 2: Tuplas: uma tupla é um argumento”Escolha esta quando houver tuplas no meio. |(name, score)| e |name, score| parecem iguais, mas são closures diferentes. A primeira recebe um argumento, uma tupla, e a desempacota. A segunda recebe dois argumentos.
Chamar uma closure de tupla com dois valores dá o E0057, e o rustc sugere colocar os parênteses:
error[E0057]: function takes 1 argument but 2 arguments were supplied --> src/main.rs:3:5 |3 | show("Ferris", 90); | ^^^^ |note: closure parameter defined herehelp: wrap these arguments in parentheses to construct a tuple |3 | show(("Ferris", 90)); | + +A ajuda diz: “coloque esses argumentos entre parênteses para montar uma tupla”.
O erro contrário acontece o tempo todo com iteradores. zip, enumerate e a iteração sobre mapas entregam à sua closure uma tupla por item. Escrever .map(|name, score| ...) dá outro código, o E0593:
error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments --> src/main.rs:7:10 |7 | .map(|name, score| format!("{name}: {score}")) | ^^^ ------------- takes 2 distinct arguments | | | expected closure that takes a single 2-tuple as argument |help: change the closure to accept a tuple instead of individual arguments |7 - .map(|name, score| format!("{name}: {score}"))7 + .map(|(name, score)| format!("{name}: {score}"))Ou seja: o map esperava uma closure que recebe uma única tupla de 2 elementos, mas a sua recebe 2 argumentos separados.
Os dois têm a mesma correção: coloque os parênteses onde está a tupla.
fn main() { let names = vec!["Ferris", "Corro"]; let scores = vec![90, 75];
// zip entrega uma tupla (name, score) por item: desempacote na lista de parâmetros let lines: Vec<String> = names .iter() .zip(scores.iter()) .map(|(name, score)| format!("{name}: {score}")) .collect(); println!("{:?}", lines);
// uma closure que recebe uma tupla é chamada com uma tupla let show = |(name, score): (&str, i32)| println!("{name} fez {score} pontos"); show(("Ferris", 90));}Saída:
["Ferris: 90", "Corro: 75"]Ferris fez 90 pontosO mesmo vale para .enumerate().map(|(i, item)| ...) e map.iter().for_each(|(key, value)| ...). Veja Iteradores e Tuplas.
Correção 3: Adapte com uma closure intermediária
Seção intitulada “Correção 3: Adapte com uma closure intermediária”Escolha esta quando você passa uma função ou closure para outra função (uma “função de ordem superior”) e as quantidades de parâmetros não batem. Aqui apply quer algo que receba um i32, mas add recebe dois. Isso dá o E0593 de novo:
error[E0593]: function is expected to take 1 argument, but it takes 2 arguments --> src/main.rs:10:26 | 5 | fn add(a: i32, b: i32) -> i32 { | ----------------------------- takes 2 arguments...10 | println!("{}", apply(add, 5)); | ----- ^^^ expected function that takes 1 argument | | | required by a bound introduced by this callEm português: “esperava-se uma função que recebe 1 argumento, mas ela recebe 2”.
Não mude o add. Embrulhe-o em uma pequena closure que tenha o formato que apply espera e que preencha sozinha o valor que falta:
fn apply<F: Fn(i32) -> i32>(f: F, x: i32) -> i32 { f(x)}
fn add(a: i32, b: i32) -> i32 { a + b}
fn main() { let bonus = 10; // recebe 1 argumento, chama add com 2 println!("{}", apply(|x| add(x, bonus), 5));
// recebe 1 tupla, chama add com as duas partes dela let pairs = vec![(1, 2), (3, 4)]; let sums: Vec<i32> = pairs.into_iter().map(|(a, b)| add(a, b)).collect(); println!("{:?}", sums);}Saída:
15[3, 7]A closure intermediária pega bonus emprestado do código ao redor, que é exatamente aquilo em que as closures são boas. Passar uma função pelo nome (apply(double, 5)) só funciona quando os parâmetros dela já batem. Veja Traits de closures.
Onde você costuma ver esse erro
Seção intitulada “Onde você costuma ver esse erro”Dentro de uma função genérica. Uma fn call_twice<F: Fn(i32)>(f: F) que chama f(2, 3) dá o E0057 com note: callable defined here, apontando para Fn(i32). O bound é a lista de parâmetros. Correção: chame f(2), ou mude o bound para Fn(i32, i32) se você realmente precisa de dois valores (aí a closure de cada chamador precisa receber dois).
Closures em Box. let f: Box<dyn Fn(i32, i32) -> i32> = Box::new(|a, b| a + b); e depois f(1) dá o E0057 com note: implementation defined here. Correção: passe os dois valores, f(1, 2).
Ordenação. v.sort_by(|a| a.cmp(a)) dá o E0593, “closure is expected to take 2 arguments, but it takes 1 argument”. O sort_by compara dois itens de cada vez. Correção: v.sort_by(|a, b| a.cmp(b)). Veja Ordenação.
Quantidade certa, tipo errado. nums.iter().map(|x: i32| x * 2) dá o E0631, “type mismatch in closure arguments” (tipos incompatíveis nos argumentos da closure), porque .iter() entrega &i32. A ajuda do rustc sugere |x: &i32|. A correção mais simples: tire a anotação, |x| x * 2.
Desempacotar algo que não é uma tupla. v.iter().map(|(a, b)| a + b) em um simples Vec<i32> dá o E0308, “expected integer, found (_, _)”. Correção: só use |(a, b)| quando os itens forem pares de verdade.
Erros relacionados
Seção intitulada “Erros relacionados”- E0061: wrong number of arguments: a mesma mensagem para funções normais, métodos e ponteiros de função.
- E0308: mismatched types: a quantidade está certa, mas um argumento (ou um padrão de tupla) tem o tipo errado.
- E0373: closure may outlive the current function: outro erro comum de closures, sobre variáveis capturadas em threads e em closures retornadas.
- E0599: no method found: pode aparecer junto com o E0631, porque uma closure com a assinatura errada quebra o resto da cadeia de iteradores.
- E0593: closure takes 2 distinct arguments: uma closure ou função passada com o número errado de parâmetros.
- E0631: type mismatch in closure arguments: a quantidade de parâmetros está certa, mas o tipo está errado.
- Todos os erros do compilador: a lista completa de páginas de erros.
Teste o que aprendeu
Seção intitulada “Teste o que aprendeu”Teste o que aprendeu
1. let double = |x: i32| x * 2; é chamada como double(2, 3). O que o rustc mostra?
2. names.iter().zip(ages.iter()).map(|n, a| ...) não compila. Qual é a correção?
3. Tanto o E0057 quanto o E0061 dizem this function takes 2 arguments but 1 argument was supplied. Como saber que você chamou uma closure?
Pontuação: 0 / 3
Para saber mais
Seção intitulada “Para saber mais”- E0057 — Rust error codes index (em inglês): a explicação oficial deste erro.
- Closures — The Rust Book (em inglês): a sintaxe das closures, a inferência de tipos dos parâmetros e as traits
Fn. - Closures — Rust by Example (em inglês): exemplos curtos e executáveis de closures, incluindo como passá-las para funções.
std::ops::Fn— standard library docs (em inglês): como bounds comoFn(i32) -> i32descrevem os parâmetros de uma closure.- E0593 — Rust error codes index (em inglês): a explicação oficial do erro de closure passada com o número errado de parâmetros.