In Rust sind Datenstrukturen standardmäßig unveränderlich. Das bedeutet, dass jede Variable oder Referenz, die ohne das Schlüsselwort mut deklariert wird, nach der Initialisierung nicht mehr geändert werden kann.
let mut value = 10; // veränderliche Variable value += 5; let value2 = 10; // unveränderliche Variable // value2 += 5; // Kompilierungsfehler: cannot assign twice to immutable variable
Die gleiche Logik gilt für Felder von Strukturen:
struct Point { x: i32, y: i32 } let mut pt = Point { x: 1, y: 2 }; pt.x = 5; // OK, da pt als mut deklariert wurde
Allerdings betrifft die Mutabilität nur die "oberste Ebene" der Variablen: Wenn die Struktur hinter einer unveränderlichen Referenz gespeichert ist, können ihre Daten nicht geändert werden, selbst wenn sie innerhalb der Struktur als mut deklariert sind.
Ein anderer Weg, die Einschränkungen zu umgehen, besteht darin, spezielle Typen wie RefCell<T> oder atomare Container zu verwenden. Dies ermöglicht es, Daten innerhalb unveränderlich aussehender Container mithilfe von „innerer Mutabilität“ (interior mutability) zu ändern, zum Beispiel:
use std::cell::RefCell; struct Counter { count: RefCell<i32>, } let counter = Counter { count: RefCell::new(0) }; *counter.count.borrow_mut() += 1; // sicher, trotz fehlendem mut
Frage: Kann man den Wert eines Strukturfelds ändern, wenn die Variable selbst nicht mit mut deklariert ist, das Feld jedoch in der Struktur ausdrücklich als mut deklariert wurde?
Typische falsche Antwort: Ja, wenn das Feld mit mut deklariert ist, kann man es ändern.
Korrekte Antwort: Das Schlüsselwort mut kann nicht verwendet werden, um ein Strukturfeld deklariert. Die Mutabilität bezieht sich nur auf die Variable selbst oder die erhaltene Referenz. Um ein Strukturfeld zu modifizieren, muss entweder die Variable als mut deklariert werden oder es müssen Typen der „inneren Mutabilität“ (z.B. RefCell) verwendet werden.
Beispiel:
struct Foo { val: i32 } // Feld wird ohne mut deklariert let mut foo = Foo { val: 1 }; foo.val = 2; // OK let foo2 = Foo { val: 3 }; foo2.val = 4; // Fehler! Variable ist nicht mutable
Geschichte
In einem großen Projekt versuchte ein Entwickler, ein Feld einer Struktur zu ändern, in dem Glauben, dass die Deklaration des Feldes mit mut ("struct S { mut x: i32 }") die benötigte Mutabilität bietet. Dies konnte nicht kompiliert werden, und der Refactoring-Prozess zog sich über mehrere Stunden, bis ihm erklärt wurde, dass Mutabilität eine Eigenschaft des Besitzes der Variable und nicht der Struktur ist.
Geschichte
In einem Projekt, das mit Multithreading zu tun hatte, basierte die gesamte Logik zur Zugriffskontrolle auf Daten in einer globalen statischen Struktur. Ohne das Wissen über die Möglichkeiten der "inneren Mutabilität" durch
RefCellschrieb das Team unnötig komplexe Mechanismen zur Sperrung und zu Race Conditions, anstatt eine einfache Lösung überArc<Mutex<T>>oderRwLock<T>zu finden.
Geschichte
Ein Entwickler vergaß, das Funktionsargument mut innerhalb der Signatur zu deklarieren, und die Funktion konnte die übergebene Struktur nicht ändern, weshalb der Fehler erst in der Produktion auftrat (Daten wurden nach dem Funktionsaufruf nicht aktualisiert). Das Wissen, dass die Übergabe standardmäßig durch eine unveränderliche Referenz erfolgt, hätte ihm erlaubt, ohne Fehler in den frühen Phasen davon zu kommen.