Dart Kurs Variablen wiederholen

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.

BegriffBedeutung
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

SchreibweiseWas bedeutet es?
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

SituationBesser geeignet
Kleines Lernskript, Zaehler hochzaehlenMutable ist okay.
Datenmodell fuer User oder AufgabeImmutable ist oft sauberer.
Liste live bearbeitenMutable kann praktisch sein.
Flutter State nachvollziehbar haltenImmutable mit Kopien ist oft besser.

15. Typische Fehler

FehlerErklaerung
final falsch verstehenFinal schuetzt die Zuweisung, nicht immer das Objekt innen.
Liste an mehreren Stellen veraendernMan verliert schnell den Ueberblick, wer was geaendert hat.
Alles mutable machenFehler werden schwerer zu finden.
Alles immutable erzwingenKann fuer einfache Aufgaben unnoetig kompliziert sein.

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

  1. Erklaere den Unterschied zwischen var, final und const.
  2. Teste eine final List<String> und fuege danach ein Element hinzu.
  3. Teste eine const List<String> und versuche ein Element hinzuzufuegen.
  4. Baue eine mutable Klasse Counter mit Methode increase().
  5. Baue eine immutable Klasse Score mit Methode increaseBy().
  6. Schreibe eine Klasse User mit copyWith.
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