Error E0061 de Rust: this function takes N arguments but M were supplied
E0061 significa que llamaste a una función con un número equivocado de argumentos: demasiado pocos o demasiados. Es uno de los errores más amables de Rust, porque rustc te dice exactamente qué argumento falta o sobra, y de qué tipo debería ser. Aparece mucho en quienes vienen de Python, JavaScript o C#, donde los argumentos por defecto y la sobrecarga son lo normal. Rust no tiene ninguna de las dos cosas, y esta página te muestra qué hacer en su lugar. Para los demás errores de esta serie, mira Errores del compilador de Rust.
El mensaje de error
Sección titulada «El mensaje de error»error[E0061]: this function takes 2 arguments but 1 argument was supplied --> src/main.rs:6:5 |6 | greet("Ferris"); // ❌ greet quiere dos argumentos | ^^^^^---------- argument #2 of type `&str` is missing |note: function defined here --> src/main.rs:1:4 |1 | fn greet(name: &str, greeting: &str) { | ^^^^^ --------------help: provide the argument |6 | greet("Ferris", /* &str */); // ❌ greet quiere dos argumentos | ++++++++++++En español: “esta función recibe 2 argumentos, pero se pasó 1”. La etiqueta dice que falta el argumento n.º 2, de tipo &str.
Este es el programa que lo provoca:
fn greet(name: &str, greeting: &str) { println!("{greeting}, {name}!");}
fn main() { greet("Ferris"); // ❌ greet quiere dos argumentos}Pasar demasiados argumentos da el mismo código, con una etiqueta “unexpected argument” (argumento inesperado) y una ayuda que dice “remove the extra argument” (quita el argumento de más):
error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> src/main.rs:6:13 |6 | let a = area(3, 4, 5); | ^^^^ - unexpected argument #3 of type `{integer}`Si es un método llamado con punto, la primera línea dice “this method takes…” (este método recibe…). Para un tuple struct como Rgb(255, 0) dice “this struct takes 3 arguments” (este struct recibe 3 argumentos). Es el mismo error en todos los casos.
Qué significa
Sección titulada «Qué significa»El mensaje tiene tres partes, y cada una ayuda:
- La primera línea cuenta: la función quiere 2 argumentos, tú le diste 1.
- La etiqueta debajo de tu llamada nombra el problema: “argument #2 of type
&stris missing” (falta el argumento n.º 2, de tipo&str). - La
note:salta a la definición de la función y subraya el parámetro que te faltó,greeting: &str.
La línea help: muestra dónde va el argumento. /* &str */ es solo un relleno que te dice el tipo; es un comentario, así que si lo pegas tal cual no compilará. Pon ahí un valor de verdad, como "Hello".
Es como una máquina de café que necesita un vaso y una moneda. Si solo metes la moneda, no te da medio café. Simplemente no arranca.
Por qué Rust hace esto
Sección titulada «Por qué Rust hace esto»En Rust, la firma de una función es un contrato exacto: estos parámetros, en este orden, con estos tipos. Cada llamada tiene que cumplirlo. No hay argumentos por defecto (greeting = "Hello"), no hay sobrecarga (dos funciones llamadas greet con parámetros distintos) y no hay funciones que reciban “cualquier número” de argumentos. Si intentas escribir un valor por defecto, obtienes error: parameter defaults are not supported (los valores por defecto de los parámetros no están soportados), y un segundo greet da E0428, “the name greet is defined multiple times” (el nombre greet está definido varias veces).
Suena estricto, pero vale la pena. Cuando lees greet(name, greeting), sabes exactamente qué función se ejecuta y qué recibe. Cuando le añades un parámetro a una función, el compilador te lista todas las llamadas que hay que actualizar, así que no se te escapa ninguna. (Cosas como println!, que sí reciben cualquier número de valores, son macros: eso es lo que significa el !. Mira Macros.)
Cómo funcionan los parámetros se explica en Funciones.
Cómo solucionarlo
Sección titulada «Cómo solucionarlo»Solución 1: Pasa exactamente lo que pide la firma
Sección titulada «Solución 1: Pasa exactamente lo que pide la firma»Elige esta casi siempre. Abre la ubicación que indica la note:, lee la lista de parámetros y pasa un valor por cada parámetro, en orden:
fn greet(name: &str, greeting: &str) { println!("{greeting}, {name}!");}
fn main() { greet("Ferris", "Hello"); greet("Corro", "Good morning");}Salida:
Hello, Ferris!Good morning, Corro!Si acabas de cambiar la función y ahora todas las llamadas están rotas, es el compilador ayudándote: arregla cada llamada que te lista, o pregúntate si el nuevo parámetro de verdad debería ser opcional (Solución 3).
Solución 2: Llama a los métodos con un punto
Sección titulada «Solución 2: Llama a los métodos con un punto»Elige esta cuando la función tiene un parámetro self. Un método normalmente se llama como valor.metodo(args). El valor que va antes del punto ocupa el lugar de self, así que no lo cuentas. Si en cambio escribes Tipo::metodo(args), nada ocupa el lugar de self:
error[E0061]: this function takes 2 arguments but 1 argument was supplied --> src/main.rs:13:5 |13 | Account::deposit(50); | ^^^^^^^^^^^^^^^^ -- argument #1 of type `&mut Account` is missing |help: provide the argument |13 | Account::deposit(/* &mut Account */, 50); | +++++++++++++++++++Aquí falta el argumento n.º 1, de tipo &mut Account: el self.
Fíjate en cómo cuenta. Si lo llamas como Account::deposit(...), rustc dice que la función recibe 2 argumentos, porque &mut self cuenta. Si lo llamas como acc.deposit(), dice que el método recibe 1 argumento, porque el punto ya aporta self. Las dos formas funcionan cuando están todos los argumentos:
struct Account { balance: i64,}
impl Account { fn deposit(&mut self, amount: i64) { self.balance += amount; }}
fn main() { let mut acc = Account { balance: 0 }; acc.deposit(50); // la forma habitual Account::deposit(&mut acc, 25); // la misma llamada, escrita completa println!("Saldo: {}", acc.balance);}Salida:
Saldo: 75En el código del día a día, usa la forma con punto. Tipo::metodo(&x, a) es útil cuando necesitas pasar el propio método a otro sitio, como team.iter().map(Player::label) (hay un ejemplo en la Solución 2 de E0424). Si una función no tiene ningún self (como new), solo se puede llamar como Tipo::funcion(...). Mira Structs y E0424.
Solución 3: Usa Option<T> para un argumento que a veces no hace falta
Sección titulada «Solución 3: Usa Option<T> para un argumento que a veces no hace falta»Elige esta cuando un argumento casi siempre tiene un valor por defecto razonable. Conviértelo en un Option, pasa None para decir “usa el valor por defecto” y rellénalo con unwrap_or:
fn connect(host: &str, port: u16, timeout_secs: Option<u64>) { let timeout = timeout_secs.unwrap_or(30); println!("Conectando a {host}:{port} (tiempo de espera {timeout}s)");}
fn main() { connect("localhost", 8080, None); connect("example.com", 443, Some(5));}Salida:
Conectando a localhost:8080 (tiempo de espera 30s)Conectando a example.com:443 (tiempo de espera 5s)Siendo sinceros: quien llama sigue escribiendo el argumento, None. Rust lo prefiere así, porque la llamada deja claro que se usa un valor por defecto. Si prefieres no escribirlo en absoluto, crea dos funciones con nombres claros, como connect(host, port), que llama a connect_with_timeout(host, port, 30). Esa es la respuesta habitual de Rust a la sobrecarga. Mira Option.
Solución 4: Usa un struct de configuración con Default
Sección titulada «Solución 4: Usa un struct de configuración con Default»Elige esta cuando una función tiene muchos ajustes y la mayoría de quienes la llaman solo cambian uno o dos. Pon los ajustes en un struct, implementa Default y deja que cada llamada rellene solo lo que necesita con ..Default::default():
struct ServerConfig { host: String, port: u16, timeout_secs: u64, verbose: bool,}
impl Default for ServerConfig { fn default() -> Self { Self { host: String::from("localhost"), port: 8080, timeout_secs: 30, verbose: false, } }}
fn start(config: ServerConfig) { println!( "Escuchando en {}:{} (tiempo de espera {}s, verbose: {})", config.host, config.port, config.timeout_secs, config.verbose );}
fn main() { start(ServerConfig::default()); start(ServerConfig { port: 3000, verbose: true, ..Default::default() });}Salida:
Escuchando en localhost:8080 (tiempo de espera 30s, verbose: false)Escuchando en localhost:3000 (tiempo de espera 30s, verbose: true)Esto también te da algo parecido a los argumentos con nombre: port: 3000 dice qué significa el número. Si el valor por defecto de cada campo es el del propio tipo (0, false, cadena vacía), #[derive(Default)] escribe el impl por ti. Para APIs más grandes, el siguiente paso es el patrón builder (Server::builder().port(3000).build()). Mira Structs y Patrones de diseño.
Dónde lo verás normalmente
Sección titulada «Dónde lo verás normalmente»Después de añadir un parámetro. Le das a fn save(path: &str) un segundo parámetro, y todas las llamadas antiguas save("notes.txt") se rompen con E0061. Solución: actualiza cada llamada que te liste el compilador, o usa la Solución 3 o la 4 si el nuevo valor suele ser el mismo.
Métodos de la biblioteca estándar. names.push("Cy", "Di") da “this method takes 1 argument but 2 arguments were supplied” (este método recibe 1 argumento, pero se pasaron 2). push añade un solo elemento. Solución: llámalo dos veces, o usa names.extend(["Cy", "Di"]). Mira Vectores.
Tuple structs. struct Rgb(u8, u8, u8); y luego Rgb(255, 0) da “this struct takes 3 arguments but 2 arguments were supplied”. Solución: da todos los campos, Rgb(255, 0, 0).
Costumbres de otros lenguajes. El greet("Ferris", greeting="Hi") de Python no es sintaxis de Rust. Escribir greet(greeting = "Hi") no nombra un argumento; rustc lo lee como una asignación a una variable llamada greeting y además informa E0425. Solución: pasa los valores por posición, o usa un struct de configuración (Solución 4).
Closures. Llamar a add(1) cuando add es |a: i32, b: i32| a + b da el mismo mensaje, pero con el código E0057 (la versión para closures). La solución es la misma: pasa los dos valores.
Errores relacionados
Sección titulada «Errores relacionados»- E0308: el número de argumentos es correcto, pero uno tiene el tipo equivocado, a menudo porque intercambiaste dos.
- E0424:
selfusado en una función que no tiene parámetroself, la otra cara de “método o función asociada”. - E0599: no existe ningún método con ese nombre, por ejemplo al llamar con punto a una función asociada como
new. - E0425: no se encuentra un valor, algo que puede aparecer junto a E0061 cuando intentas usar argumentos con nombre.
- Todos los errores del compilador: la lista completa de páginas de errores. También relacionados: E0057 (closure llamada con un número equivocado de argumentos) y E0428 (una función definida dos veces, al intentar sobrecargarla), que no tiene página propia.
Comprueba lo que aprendiste
Sección titulada «Comprueba lo que aprendiste»Comprueba lo aprendido
1. fn area(w: u32, h: u32) -> u32 se llama como area(5). ¿Qué informa rustc?
2. Un método es fn deposit(&mut self, amount: i64). ¿Qué llamada es correcta?
3. Quieres un argumento timeout que a la mayoría de quienes llaman no les importa. ¿Cuál es un enfoque habitual en Rust?
Puntuación: 0 / 3
Para leer más
Sección titulada «Para leer más»- E0061 — Rust error codes index (en inglés): la explicación oficial de este error.
- Functions — The Rust Book (en inglés): parámetros, tipos en las firmas y cómo funcionan las llamadas.
- Method Syntax — The Rust Book (en inglés): por qué el punto rellena
self, y las funciones asociadas comonew. - Trait
Default— documentación de la biblioteca estándar (en inglés): cómo derivarDefaulty usar..Default::default(). - Builder pattern — Rust Design Patterns (en inglés): el sustituto habitual de las listas de argumentos largas y de los argumentos opcionales.