Rust-Fehler E0384: cannot assign twice to immutable variable (fehlendes mut)
E0384 bedeutet: Du hast einer Variablen einen Wert gegeben und willst ihr danach einen anderen Wert geben – aber die Variable wurde nicht mit mut angelegt. In Rust lassen sich Variablen nur ändern, wenn du das ausdrücklich sagst. Fast jeder stolpert in seiner ersten Stunde mit Rust über diesen Fehler, und die Lösung sind meistens drei Buchstaben: mut. Diese Seite zeigt dir zuerst die Lösung und erklärt dann, warum Rust so arbeitet. Die anderen Fehler dieser Reihe findest du unter Rust-Compilerfehler.
Die Fehlermeldung
Abschnitt betitelt „Die Fehlermeldung“error[E0384]: cannot assign twice to immutable variable `score` --> src/main.rs:4:5 |2 | let score = 10; | ----- first assignment to `score`3 | println!("Score: {score}");4 | score = 15; // ❌ score ist nicht mut | ^^^^^^^^^^ cannot assign twice to immutable variable |help: consider making this binding mutable |2 | let mut score = 10; | +++Auf Deutsch heißt das ungefähr: „Einer unveränderbaren Variablen kann nicht zweimal ein Wert zugewiesen werden.“ Dieses Programm erzeugt die Meldung:
fn main() { let score = 10; println!("Score: {score}"); score = 15; // ❌ score ist nicht mut println!("New score: {score}");}Ist die Variable ein Funktionsparameter, lautet die Meldung etwas anders: „cannot assign to immutable argument“ (einem unveränderbaren Argument kann nichts zugewiesen werden). Es ist derselbe Fehlercode und dieselbe Idee.
Was sie bedeutet
Abschnitt betitelt „Was sie bedeutet“Der Compiler zeigt auf zwei Stellen:
- Zeile 2, markiert mit
first assignment to score(erste Zuweisung anscore): Hier hatscoreseinen Wert bekommen. Weil in der Zeileletsteht und nichtlet mut, ist dieser Wert endgültig. - Zeile 4, markiert mit
^^^^: Hier versuchst du, einen neuen Wert hineinzuschreiben. Rust lehnt das ab.
Der Teil help: zeigt schon die Lösung: let mut score = 10;. Die +++ markieren die drei Zeichen, die du ergänzen musst.
Stell dir let wie Schreiben mit Kugelschreiber vor und let mut wie Schreiben mit Bleistift. Beides ist in Ordnung. Aber was du mit Kugelschreiber geschrieben hast, kannst du später nicht wegradieren.
Dieselbe Regel gilt für +=, -=, *= und ihre Verwandten. Auch count += 1 ist eine Zuweisung und braucht deshalb mut.
Warum Rust das macht
Abschnitt betitelt „Warum Rust das macht“In Rust ist jede Variable standardmäßig unveränderbar. Wenn sie sich ändern soll, musst du das mit mut ausdrücklich erlauben. Mehr dazu steht auf der Seite Variablen.
Das klingt streng, hilft dir aber sehr. Wenn du let total = ... liest, weißt du: total behält diesen Wert bis zum Ende seines Gültigkeitsbereichs (Scope). Du musst nicht den Rest der Funktion absuchen, ob irgendetwas ihn verändert. Siehst du dagegen let mut, ist das ein klares Signal: „Pass auf, dieser Wert ändert sich.“
Außerdem fängt die Regel echte Bugs ab. Wenn du eigentlich eine Kopie ändern wolltest und aus Versehen ins Original schreibst, oder wenn du einen Namen versehentlich wiederverwendest, hält dich der Compiler auf. Und Rust warnt dich vor mut-Variablen, die sich nie ändern (variable does not need to be mutable, die Variable muss nicht veränderbar sein). So bleibt das Signal in beide Richtungen ehrlich.
So behebst du den Fehler
Abschnitt betitelt „So behebst du den Fehler“Lösung 1: mut hinzufügen
Abschnitt betitelt „Lösung 1: mut hinzufügen“Nimm diese Lösung, wenn sich die Variable wirklich mit der Zeit ändern soll: ein Zähler, eine laufende Summe, ein Punktestand, ein Zustand. Meistens ist das die richtige Lösung, und genau sie schlägt auch der Compiler vor.
fn main() { let mut score = 10; println!("Punktestand: {score}"); score = 15; // ✅ jetzt erlaubt println!("Neuer Punktestand: {score}");
let mut count = 0; for _ in 0..3 { count += 1; } println!("Zähler: {count}");}Ausgabe:
Punktestand: 10Neuer Punktestand: 15Zähler: 3Der Zähler ist der klassische Fall: let count = 0; und danach count += 1; in einer Schleife ergibt E0384 in der Zeile mit +=. Ein mut behebt das. Siehe Eine Variable mit mut veränderbar machen.
Lösung 2: Shadowing für einen neuen Wert
Abschnitt betitelt „Lösung 2: Shadowing für einen neuen Wert“Nimm diese Lösung, wenn du die Variable eigentlich gar nicht ändern willst. Du willst einen neuen Wert, der aus dem alten berechnet wird, oft in ein paar Schritten – und danach bleibt er gleich. Schreib dafür einfach noch einmal let mit demselben Namen:
fn main() { let price = 20; let price = price + 5; // ein neues `price`, gebaut aus dem alten let price = price * 2; println!("Endpreis: {price}");
let input = " 42 "; let input = input.trim(); // immer noch Text let input: u32 = input.parse().unwrap(); // jetzt eine Zahl println!("Eingelesen: {}", input + 1);}Ausgabe:
Endpreis: 50Eingelesen: 43Das nennt man Shadowing (Verschatten): Jedes let legt eine ganz neue Variable an, die die alte verdeckt. Das bringt dir zwei Vorteile. Das endgültige price ist unveränderbar, also kann es später nichts aus Versehen ändern. Und der Typ darf sich ändern – input wird von &str zu u32. Das kann mut nicht. Mehr dazu in Shadowing: denselben Namen wiederverwenden.
Eine einfache Faustregel: Ändert sich der Wert immer wieder (in einer Schleife, im Lauf der Zeit), nimm mut. Bereitest du einen Wert in ein paar Schritten vor, liest sich Shadowing schön.
Lösung 3: mut an einen Funktionsparameter schreiben
Abschnitt betitelt „Lösung 3: mut an einen Funktionsparameter schreiben“Nimm diese Lösung, wenn eine Funktion ihre eigene Kopie eines Arguments ändern will. Auch Parameter sind unveränderbar, deshalb schlägt das hier fehl:
fn countdown(n: u32) { while n > 0 { println!("{n}..."); n -= 1; // ❌ cannot assign to immutable argument `n` } println!("Liftoff!");}error[E0384]: cannot assign to immutable argument `n` --> src/main.rs:4:9 |4 | n -= 1; // ❌ cannot assign to immutable argument `n` | ^^^^^^ cannot assign to immutable argument |help: consider making this binding mutable |1 | fn countdown(mut n: u32) { | +++Der Compiler sagt dir: Dem unveränderbaren Argument n kann nichts zugewiesen werden. Schreib mut vor den Namen des Parameters:
fn countdown(mut n: u32) { while n > 0 { println!("{n}..."); n -= 1; } println!("Abheben!");}
fn main() { let start = 3; countdown(start); println!("start ist immer noch {start}");}Ausgabe:
3...2...1...Abheben!start ist immer noch 3Achte darauf, dass sich start in main nicht geändert hat. mut n macht nur die eigene Kopie der Funktion veränderbar. Der Aufrufer braucht kein mut und merkt davon nichts. Soll die Funktion die Variable des Aufrufers ändern, nimm stattdessen einen &mut u32 als Parameter und übergib &mut start. Siehe Funktionen und Borrowing.
Wo du ihn oft siehst
Abschnitt betitelt „Wo du ihn oft siehst“Die Variable einer for-Schleife ändern. Die Schleifenvariable ist bei jedem Durchlauf eine frische, unveränderbare Variable:
for i in 0..5 { if i == 2 { i += 1; // ❌ cannot assign twice to immutable variable `i` } println!("{i}");}Lösung: Den Schleifenzähler selbst willst du selten ändern. Spring mit continue weiter, nimm .step_by(2) oder – wenn du die volle Kontrolle brauchst – wechsle zu einer while-Schleife mit let mut i. (for mut i in 0..5 kompiliert zwar, ändert aber nur die Kopie dieses Durchlaufs und überspringt nichts.) Siehe break und continue und while-Schleifen.
Erst deklarieren, später zuweisen. let total; ohne Wert ist erlaubt, und du darfst einmal etwas zuweisen. Eine zweite Zuweisung ergibt E0384:
let total;total = 5;total = 6; // ❌ cannot assign twice to immutable variable `total`Lösung: Ändert sich der Wert wirklich, nimm let mut total. Wolltest du nur einen von zwei Werten auswählen, berechne ihn in einem einzigen Ausdruck: let total = if big_order { 6 } else { 5 };. Siehe if / else.
Eine Summe aufaddieren. let sum = 0; und danach sum += price; in einer Schleife ist das häufigste E0384 überhaupt. Lösung: let mut sum = 0; – oder du sparst dir die Variable und schreibst let sum: u32 = prices.iter().sum();. Siehe Iteratoren.
Verwandte Fehler
Abschnitt betitelt „Verwandte Fehler“- E0596: cannot borrow as mutable, as it is not declared as mutable (kann nicht veränderbar ausgeliehen werden). Dasselbe „
mutvergessen“-Problem, aber beim Aufruf einer ändernden Methode wie.push()statt bei einer Zuweisung. - E0594: cannot assign to
p.hp, aspis not declared as mutable. Den siehst du, wenn du einem Struct-Feld etwas zuweist (p.hp = 5;) oder über eine&-Referenz schreibst. Lösung:let mut poder eine&mut-Referenz. Siehe Ein Struct veränderbar machen. - E0502: Du wolltest einen Wert ändern, während er zum Lesen ausgeliehen war.
- E0382: Du hast einen Wert benutzt, nachdem er verschoben (moved) wurde.
- Alle Compilerfehler: die vollständige Liste der Fehlerseiten.
Kurzer Check
Abschnitt betitelt „Kurzer Check“Kurzer Check
1. Du schreibst let lives = 3; und später lives -= 1;. Warum bekommst du E0384?
2. Du willst name einmal aufräumen (trimmen und in Großbuchstaben umwandeln) und danach nie wieder ändern. Was liest sich am besten?
3. fn halve(n: u32) macht n /= 2; und bekommt E0384. Welche Lösung lässt den Aufrufer unverändert?
Punkte: 0 / 3
Weiterlesen
Abschnitt betitelt „Weiterlesen“- E0384 – Rust error codes index (auf Englisch): die offizielle Erklärung dieses Fehlers, mit einem Beispiel.
- Variablen und Veränderbarkeit – Das Rust-Buch: das Kapitel zu
let,mut, Konstanten und Shadowing. - Mutability – Rust by Example (auf Englisch): ein kurzes lauffähiges Beispiel für
letim Vergleich zulet mut. - Freezing – Rust by Example (auf Englisch): wie Shadowing eine veränderbare Variable mit einer unveränderbaren „einfriert“.