Lektion 03 - Mutable & Immutable
Verstehen, was veraenderbar ist und was nicht
Mutable bedeutet veraenderbar. Immutable bedeutet unveraenderbar. Dieses Thema ist extrem wichtig, weil du dadurch besser verstehst, warum sich manche Werte aendern, warum andere Werte fest bleiben und warum Flutter oft mit unveraenderlichen Daten arbeitet.
1. Die Grundidee
Ein Wert ist mutable, wenn er nach dem Erstellen veraendert werden kann. Ein Wert ist immutable, wenn er nach dem Erstellen nicht mehr veraendert werden kann.
mutableDer Inhalt kann sich spaeter aendern.immutableDer Inhalt bleibt nach dem Erstellen gleich.variableEin Name, der auf einen Wert zeigt.valueDer eigentliche gespeicherte Wert.Wichtig: Es gibt einen Unterschied zwischen "die Variable zeigt auf etwas anderes" und "das Objekt selbst wird veraendert".
2. Veraenderbare Variable mit var
Mit var kann Dart den Typ automatisch erkennen. Die Variable darf danach auf
einen neuen Wert desselben Typs zeigen.
var points = 10;
points = 15;
points = points + 5;
print(points); // 20
points ist hier veraenderbar. Der alte Wert wird ersetzt.
3. Feste Variable mit final
final bedeutet: Diese Variable wird einmal gesetzt und kann danach nicht mehr
neu zugewiesen werden.
final name = 'Mina';
// Fehler:
name = 'Alex';
Du kannst dir final so merken: Der Name darf nach dem ersten Speichern nicht
mehr auf einen anderen Wert zeigen.
4. final macht nicht automatisch alles immutable
Das ist ein sehr wichtiger Punkt. Eine final-Variable kann nicht neu zugewiesen
werden. Aber wenn sie auf ein veraenderbares Objekt zeigt, kann dieses Objekt trotzdem
veraendert werden.
final names = ['Mina', 'Alex'];
names.add('Sam');
print(names); // [Mina, Alex, Sam]
// Fehler:
names = ['Neu'];
names darf nicht auf eine neue Liste zeigen. Die Liste selbst ist aber mutable
und kann Eintraege bekommen.
5. const: wirklich feste Werte
const steht fuer Konstanten. Der Wert muss schon zur Compile-Zeit feststehen.
Eine const-Liste kann nicht veraendert werden.
const topics = ['Dart', 'Flutter'];
// Fehler:
topics.add('OOP');
const ist staerker als final. final bedeutet: einmal setzen.
const bedeutet: echter konstanter Wert.
6. Vergleich: var, final, const
var age = 18;Variable darf spaeter einen neuen int-Wert bekommen.final age = 18;Variable wird einmal gesetzt und nicht neu zugewiesen.const age = 18;Wert ist eine feste Konstante.final list = [];Name bleibt gleich, Liste kann trotzdem veraendert werden.const list = [];Liste selbst ist unveraenderbar.7. Primitive Werte wirken immutable
Zahlen, Booleans und Strings werden nicht direkt "innen" veraendert. Wenn du einen neuen Wert berechnest, entsteht ein neuer Wert und die Variable zeigt darauf.
var text = 'Hallo';
text = text + ' Dart';
var count = 3;
count = count + 1;
Der alte Text wird nicht umgebaut. Stattdessen entsteht ein neuer Text
'Hallo Dart'.
8. Listen sind meistens mutable
Eine normale Dart-Liste kann veraendert werden: Du kannst Elemente hinzufuegen, entfernen oder ersetzen.
final tasks = ['Lesen', 'Ueben'];
tasks.add('Testen');
tasks[0] = 'Wiederholen';
tasks.remove('Ueben');
print(tasks);
Das ist praktisch, aber es kann auch Fehler verursachen, wenn viele Stellen im Programm dieselbe Liste veraendern.
9. Immutable arbeiten: Kopie statt Aenderung
Bei immutable Denken veraenderst du die alte Liste nicht. Du erstellst eine neue Liste mit den gewuenschten Aenderungen.
final oldTasks = ['Lesen', 'Ueben'];
final newTasks = [...oldTasks, 'Testen'];
print(oldTasks); // [Lesen, Ueben]
print(newTasks); // [Lesen, Ueben, Testen]
... ist der Spread-Operator. Er packt die alten Eintraege in eine neue Liste.
10. Objekte mutable machen
Eine Klasse ist mutable, wenn ihre Attribute veraenderbar sind oder Methoden den inneren Zustand aendern.
class Counter {
int value;
Counter(this.value);
void increase() {
value++;
}
}
void main() {
final counter = Counter(0);
counter.increase();
print(counter.value); // 1
}
Obwohl counter final ist, kann das Objekt innen geaendert werden.
11. Objekte immutable machen
Eine Klasse wird deutlich immutabler, wenn alle Attribute final sind und keine
Methode den Zustand im Objekt veraendert.
class Score {
final int value;
const Score(this.value);
Score increaseBy(int amount) {
return Score(value + amount);
}
}
void main() {
const oldScore = Score(10);
final newScore = oldScore.increaseBy(5);
print(oldScore.value); // 10
print(newScore.value); // 15
}
increaseBy veraendert nicht das alte Objekt. Die Methode erstellt ein neues
Score-Objekt mit neuem Wert.
12. copyWith: Standardmuster fuer immutable Objekte
In Dart und Flutter sieht man oft copyWith. Damit wird ein Objekt kopiert und
nur bestimmte Werte werden ersetzt.
class User {
final String name;
final int points;
const User({
required this.name,
required this.points,
});
User copyWith({
String? name,
int? points,
}) {
return User(
name: name ?? this.name,
points: points ?? this.points,
);
}
}
void main() {
const user = User(name: 'Mina', points: 10);
final updatedUser = user.copyWith(points: 20);
print(user.points); // 10
print(updatedUser.points); // 20
}
?? bedeutet: Wenn links ein Wert vorhanden ist, nutze ihn. Sonst nutze den
rechten Ersatzwert.
13. Warum Flutter immutable liebt
Flutter baut Oberflaechen staendig neu. Widgets sind deshalb meistens immutable: Sie beschreiben nur, wie etwas aussehen soll. Wenn sich Daten aendern, wird ein neuer Zustand erzeugt und Flutter zeichnet passend neu.
class ProfileTitle extends StatelessWidget {
final String name;
const ProfileTitle({
super.key,
required this.name,
});
@override
Widget build(BuildContext context) {
return Text(name);
}
}
name ist final, weil das Widget selbst nicht spaeter innen
umgebaut werden soll. Wenn ein anderer Name angezeigt werden soll, entsteht ein neues
Widget mit neuen Daten.
14. Mutable vs. Immutable im Alltag
15. Typische Fehler
final falsch verstehenFinal schuetzt die Zuweisung, nicht immer das Objekt innen.16. Immutable Update planen
Bei immutable Updates denkst du nicht: "Aendere das alte Objekt", sondern: "Erstelle eine neue Version mit geaenderten Daten".
Funktion addTask(oldTasks, newTask):
Erstelle neue Liste
Fuege alle Eintraege aus oldTasks ein
Fuege newTask ans Ende ein
Gib neue Liste zurueck
Wichtig:
oldTasks bleibt unveraendert
17. Aufgaben zu Mutable & Immutable
- Erklaere den Unterschied zwischen
var,finalundconst. - Teste eine
final List<String>und fuege danach ein Element hinzu. - Teste eine
const List<String>und versuche ein Element hinzuzufuegen. - Baue eine mutable Klasse
Countermit Methodeincrease(). - Baue eine immutable Klasse
Scoremit MethodeincreaseBy(). - Schreibe eine Klasse
UsermitcopyWith.
Mini-Aufgabe:
class Todo {
final String title;
final bool isDone;
const Todo(this.title, this.isDone);
}
Ergaenze:
- copyWith
- Methode markDone()
- Kurz planen, welche neue Version entstehen soll
Weiter zu Null Safety