Rust-Fehler E0057: this function takes N arguments but M were supplied (Closures)
E0057 bedeutet: Du hast ein Closure (eine anonyme Funktion) mit der falschen Anzahl von Argumenten aufgerufen – mit zu wenigen oder zu vielen. Es ist die Closure-Variante von E0061, und die Meldung liest sich fast genauso. Die Lösung geht meistens schnell: Schau dir das |...| des Closures an und übergib einen Wert pro Parameter. Diese Seite behandelt auch zwei nahe Verwandte, die dir bei Iteratoren begegnen, E0593 und E0631, weil sie aus derselben Verwechslung entstehen. Die anderen Fehler dieser Reihe findest du unter Rust-Compilerfehler.
Die Fehlermeldung
Abschnitt betitelt „Die Fehlermeldung“error[E0057]: this function takes 2 arguments but 1 argument was supplied --> src/main.rs:3:17 |3 | let total = add(1); // ❌ add will zwei Zahlen | ^^^--- 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 will zwei Zahlen | +++++++++++Auf Deutsch heißt das ungefähr: „Diese Funktion nimmt 2 Argumente, aber es wurde 1 Argument übergeben.“ Dieses Programm erzeugt die Meldung:
fn main() { let add = |a: i32, b: i32| a + b; let total = add(1); // ❌ add will zwei Zahlen println!("{total}");}Zu viele Argumente führen zum selben Code, mit einem Label „unexpected argument“ (unerwartetes Argument) und dem Hinweis „remove the extra argument“ (entferne das überzählige Argument):
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 hereWas sie bedeutet
Abschnitt betitelt „Was sie bedeutet“Lies die Meldung wie die für Funktionen: Die erste Zeile zählt (das Closure nimmt 2, du hast 1 übergeben), das Label unter deinem Aufruf nennt das fehlende oder überzählige Argument, und help: zeigt, wo es hingehört. /* i32 */ ist nur ein Platzhalter-Kommentar, der dir den Typ nennt. Setz dort einen echten Wert ein.
E0057 oder E0061? Die erste Zeile ist gleich. Die note: verrät den Unterschied:
closure defined here(Closure hier definiert): Du hast ein Closure aufgerufen. Das ist E0057.callable defined here(Aufrufbares hier definiert): Du hast ein generischesfmit einem Bound wieF: Fn(i32)aufgerufen. Auch E0057.function defined here(Funktion hier definiert): eine normalefn, eine Methode oder ein Funktionszeiger (let f: fn(i32, i32) -> i32 = add;). Das ist E0061.
In jedem Fall ist die Lösung dieselbe: Bring den Aufruf mit der Parameterliste in Einklang.
Warum Rust das macht
Abschnitt betitelt „Warum Rust das macht“Die Parameterliste eines Closures ist genauso fest wie die einer Funktion. |a: i32, b: i32| nimmt genau zwei i32, jedes Mal. Es gibt keine Standardargumente und kein „gib ruhig weniger, wenn du magst“. Selbst wenn du die Typen weglässt, leitet rustc sie aus dem Rumpf des Closures und seiner ersten Verwendung ab – und ab dann stehen sie fest.
Unter der Haube implementiert ein Closure einen der Fn-Traits mit einer festen Liste von Argumenttypen, etwa Fn(i32, i32) -> i32. Der Compiler prüft jeden Aufruf gegen diese Liste. Ein Aufruf mit der falschen Anzahl erreicht dein laufendes Programm also nie. Wie Closures und ihre Parameter funktionieren, erfährst du in Closures und Closure-Traits.
So behebst du den Fehler
Abschnitt betitelt „So behebst du den Fehler“Lösung 1: Den Aufruf an die Parameter des Closures anpassen
Abschnitt betitelt „Lösung 1: Den Aufruf an die Parameter des Closures anpassen“Nimm diese Lösung fast immer. Spring zur Stelle aus der note:, zähl die Parameter zwischen den senkrechten Strichen |...| und übergib für jeden einen Wert. Hast du mehr Werte als Parameter, ruf das Closure mehrmals auf:
fn main() { let add = |a: i32, b: i32| a + b; let greet = |name: &str| println!("Hallo, {name}!");
let total = add(1, 2); println!("{total}");
greet("Ferris"); greet("Corro"); // ein Aufruf pro Name}Ausgabe:
3Hallo, Ferris!Hallo, Corro!Soll das Closure wirklich eine andere Anzahl von Werten nehmen, ändere stattdessen das Closure. Auch das ist in Ordnung, solange jeder Aufruf dazu passt.
Lösung 2: Tupel – ein Tupel ist ein Argument
Abschnitt betitelt „Lösung 2: Tupel – ein Tupel ist ein Argument“Nimm diese Lösung, wenn Tupel im Spiel sind. |(name, score)| und |name, score| sehen ähnlich aus, sind aber verschiedene Closures. Das erste nimmt ein Argument, ein Tupel, und packt es aus. Das zweite nimmt zwei Argumente.
Rufst du ein Tupel-Closure mit zwei Werten auf, bekommst du E0057, und rustc schlägt vor, Klammern zu ergänzen:
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)); | + +Der umgekehrte Fehler passiert ständig bei Iteratoren. zip, enumerate und das Durchlaufen einer Map geben deinem Closure ein Tupel pro Element. Schreibst du .map(|name, score| ...), bekommst du einen anderen Code, 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}"))Auf Deutsch: „Das Closure soll ein einzelnes 2-Tupel als Argument nehmen, nimmt aber 2 einzelne Argumente.“ Beide Fehler haben dieselbe Lösung: Setz die Klammern dorthin, wo das Tupel ist.
fn main() { let names = vec!["Ferris", "Corro"]; let scores = vec![90, 75];
// zip liefert ein (name, score)-Tupel pro Element: in der Parameterliste auspacken let lines: Vec<String> = names .iter() .zip(scores.iter()) .map(|(name, score)| format!("{name}: {score}")) .collect(); println!("{:?}", lines);
// ein Closure, das ein Tupel nimmt, wird mit einem Tupel aufgerufen let show = |(name, score): (&str, i32)| println!("{name} hat {score} Punkte"); show(("Ferris", 90));}Ausgabe:
["Ferris: 90", "Corro: 75"]Ferris hat 90 PunkteDasselbe gilt für .enumerate().map(|(i, item)| ...) und map.iter().for_each(|(key, value)| ...). Siehe Iteratoren und Tupel.
Lösung 3: Mit einem Wrapper-Closure anpassen
Abschnitt betitelt „Lösung 3: Mit einem Wrapper-Closure anpassen“Nimm diese Lösung, wenn du eine Funktion oder ein Closure an eine andere Funktion übergibst (eine „Funktion höherer Ordnung“) und die Parameterzahlen nicht zusammenpassen. Hier will apply etwas, das ein i32 nimmt, aber add nimmt zwei. Das führt wieder zu E0593:
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 callÄndere add nicht. Verpack es in ein kleines Closure, das die Form hat, die apply erwartet, und den fehlenden Wert selbst ergänzt:
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; // nimmt 1 Argument, ruft add mit 2 auf println!("{}", apply(|x| add(x, bonus), 5));
// nimmt 1 Tupel, ruft add mit seinen beiden Teilen auf let pairs = vec![(1, 2), (3, 4)]; let sums: Vec<i32> = pairs.into_iter().map(|(a, b)| add(a, b)).collect(); println!("{:?}", sums);}Ausgabe:
15[3, 7]Der Wrapper leiht sich bonus aus dem umgebenden Code – genau dafür sind Closures gut. Eine Funktion direkt beim Namen zu übergeben (apply(double, 5)), klappt nur, wenn ihre Parameter schon passen. Siehe Closure-Traits.
Wo du ihn oft siehst
Abschnitt betitelt „Wo du ihn oft siehst“In einer generischen Funktion. Ruft fn call_twice<F: Fn(i32)>(f: F) intern f(2, 3) auf, bekommst du E0057 mit note: callable defined here, und die Notiz zeigt auf Fn(i32). Der Bound ist die Parameterliste. Lösung: Ruf f(2) auf, oder ändere den Bound zu Fn(i32, i32), wenn du wirklich zwei Werte brauchst (dann muss das Closure jedes Aufrufers zwei nehmen).
Closures in einer Box. let f: Box<dyn Fn(i32, i32) -> i32> = Box::new(|a, b| a + b); und dann f(1) führt zu E0057 mit note: implementation defined here. Lösung: Übergib beide Werte, f(1, 2).
Sortieren. v.sort_by(|a| a.cmp(a)) führt zu E0593, „closure is expected to take 2 arguments, but it takes 1 argument“ (das Closure soll 2 Argumente nehmen, nimmt aber 1). sort_by vergleicht immer zwei Elemente. Lösung: v.sort_by(|a, b| a.cmp(b)). Siehe Sortieren.
Richtige Anzahl, falscher Typ. nums.iter().map(|x: i32| x * 2) führt zu E0631, „type mismatch in closure arguments“ (Typkonflikt bei den Closure-Argumenten), weil .iter() &i32 liefert. rustc schlägt |x: &i32| vor. Am einfachsten: Lass die Annotation weg, |x| x * 2.
Etwas auspacken, das kein Tupel ist. v.iter().map(|(a, b)| a + b) auf einem einfachen Vec<i32> führt zu E0308, „expected integer, found (_, _)“. Lösung: Nimm |(a, b)| nur, wenn die Elemente wirklich Paare sind.
Verwandte Fehler
Abschnitt betitelt „Verwandte Fehler“- E0061: wrong number of arguments: dieselbe Meldung für normale Funktionen, Methoden und Funktionszeiger.
- E0308: mismatched types: Die Anzahl stimmt, aber ein Argument (oder ein Tupel-Pattern) hat den falschen Typ.
- E0373: closure may outlive the current function: ein weiterer häufiger Closure-Fehler, bei dem es um eingefangene Variablen in Threads und zurückgegebenen Closures geht.
- E0599: no method found: kann neben E0631 auftauchen, weil ein Closure mit falscher Signatur den Rest einer Iterator-Kette durcheinanderbringt.
- E0593: closure takes 2 distinct arguments: ein Closure oder eine Funktion mit der falschen Anzahl von Parametern übergeben.
- E0631: type mismatch in closure arguments: Die Anzahl der Parameter stimmt, aber der Typ ist falsch.
- Alle Compilerfehler: die vollständige Liste der Fehlerseiten.
Kurzer Check
Abschnitt betitelt „Kurzer Check“Kurzer Check
1. let double = |x: i32| x * 2; wird als double(2, 3) aufgerufen. Was meldet rustc?
2. names.iter().zip(ages.iter()).map(|n, a| ...) kompiliert nicht. Was ist die Lösung?
3. E0057 und E0061 sagen beide this function takes 2 arguments but 1 argument was supplied. Woran erkennst du, dass du ein Closure aufgerufen hast?
Punkte: 0 / 3
Weiterlesen
Abschnitt betitelt „Weiterlesen“- E0057 – Rust error codes index (auf Englisch): die offizielle Erklärung dieses Fehlers.
- Closures – Das Rust-Buch: Closure-Syntax, Typableitung für Parameter und die
Fn-Traits. - Closures – Rust by Example (auf Englisch): kurze lauffähige Beispiele für Closures, auch dafür, wie man sie an Funktionen übergibt.
std::ops::Fn– Doku der Standardbibliothek (auf Englisch): wie Bounds wieFn(i32) -> i32die Parameter eines Closures beschreiben.- E0593 – Rust error codes index (auf Englisch): die offizielle Erklärung des Fehlers, wenn ein Closure mit der falschen Anzahl von Parametern übergeben wird.