Einleitung: Das Rätsel der zwei «mut»
\nWenn Sie jemals in Rust programmiert haben, ist Ihnen sicherlich die seltsame Doppelnatur des Schlüsselworts mut aufgefallen. Es kann sowohl vor dem Variablennamen stehen (let mut x = 5) als auch nach dem Doppelpunkt, neben dem Typ (&mut T). Auf den ersten Blick eine Kleinigkeit, aber auf Stack Overflow hat dieses Thema tausende von Aufrufen gesammelt. Warum? Weil sich hinter dieser Kleinigkeit ein grundlegender Unterschied zwischen Ownership und Referenz verbirgt.
In diesem Artikel beantworten wir nicht nur die Frage «Wohin setzt man mut?». Wir schauen unter die Haube von Rust, analysieren, wie der Compiler Mutabilität behandelt und warum dieser Unterschied der Schlüssel zur sicheren Speicherverwaltung ist. Wenn Sie Rust lernen oder sein Ownership-Modell tiefer verstehen wollen, sind Sie hier genau richtig.
\n\nHauptteil: Zwei Welten – zwei mut
\n1. Das erste mut: «Ich bin der Eigentümer und kann mich ändern»
\nWenn Sie schreiben:
\nlet mut x = 42;\nx = 10; // ok\n\nsagen Sie dem Compiler: «Ich erstelle eine Variable x, die den Wert 42 besitzt, und ich erlaube, diesen Wert später zu ändern». Ohne mut ist die Variable standardmäßig unveränderlich (immutable). Dies ist eine bewusste Designentscheidung von Rust: Standardmäßig Sicherheit, Mutation ist eine explizite Erlaubnis.
Unter der Haube: Der Compiler reserviert Speicher auf dem Stack (oder Heap, wenn es ein Box ist) und markiert die Speicherzelle als «veränderbar». Der Borrow Checker wird überwachen, dass Sie nicht gleichzeitig eine veränderbare und eine unveränderbare Referenz auf diesen Speicher haben. Wenn mut nicht gesetzt wäre, würde jeder Versuch, einen neuen Wert zuzuweisen, einen Kompilierungsfehler auslösen.
2. Das zweite mut: «Ich gebe dir die Schlüssel, aber nicht das Haus»
\nNun ein Beispiel mit einer Referenz:
\nlet mut x = 42;\nlet y = &mut x; // veränderbare Referenz auf x\n*y = 100;\n\nHier geht es bei &mut T nicht um Ownership, sondern um Borrowing. Wir sagen: «Ich leihe x an die Variable y aus und gebe ihr das Recht, es zu ändern». x selbst bleibt der Eigentümer, übergibt aber vorübergehend die Kontrolle.
Der entscheidende Unterschied: mut nach dem Doppelpunkt bezieht sich auf den Typ der Referenz, nicht auf die Variable. Sie können nicht let &mut x = &y schreiben – das ist syntaktisch falsch. Rust unterscheidet streng:
- \n
let mut x– veränderbare Variable als Eigentümer \n&mut T– veränderbare Referenz auf einen Wert vom Typ T \n
Genau diese Unterscheidung verwirrt Anfänger: Visuell steht «mut» an verschiedenen Stellen, semantisch löst es jedoch unterschiedliche Aufgaben.
\n\n3. Warum das wichtig ist: Der Borrow Checker
\nStellen Sie sich vor, Sie schreiben eine Funktion, die eine Referenz entgegennimmt:
\nfn increment(n: &mut i32) {\n *n += 1;\n}\n\nfn main() {\n let mut a = 5;\n increment(&mut a);\n println!("{}", a); // 6\n}\n\nWenn wir fn increment(n: &i32) (ohne mut) schreiben würden, könnten wir n nicht ändern. Und wenn wir das mut bei a vergessen hätten, könnten wir keine veränderbare Referenz übergeben. Der Rust-Compiler schützt Sie vor versehentlichen Datenänderungen, die zu Datenrennen oder undefiniertem Verhalten führen könnten.
Unter der Haube: &mut T ist eine eindeutige (exklusive) Referenz. Zu jedem Zeitpunkt kann es nur eine veränderbare Referenz auf die Daten geben. Diese Regel garantiert, dass niemand anderes die Daten liest, während Sie sie ändern. Unveränderbare Referenzen können beliebig viele existieren – sie lesen nur.
4. Praxisbeispiel: Strukturen und Methoden
\nHäufig entsteht Verwirrung bei der Arbeit mit Methoden:
\nstruct Point {\n x: i32,\n y: i32,\n}\n\nimpl Point {\n fn shift(&mut self, dx: i32, dy: i32) {\n self.x += dx;\n self.y += dy;\n }\n}\n\nfn main() {\n let mu