I. Grundlegende if / if-else Verzweigungen
- In den Klammern von
ifmuss stets ein boolescher Ausdruck stehen; eine implizite Umwandlung zum Boolean ist nicht erlaubt. - Mehrere
else if-Blöcke können hintereinander geschrieben werden, optional folgt am Ende einelse. - Bei einzeiligem Code lassen sich geschweifte Klammern weglassen, zur besseren Lesbarkeit empfiehlt es sich, sie durchgängig zu setzen.
void main() {
bool isRaining = false;
bool isSnowing = true;
if (isRaining) {
print("Regenmantel mitnehmen");
} else if (isSnowing) {
print("Dickere Jacke anziehen");
} else {
print("Cabrio fahren");
}
}Code-Sprache: Dart (dart)
Ausgabeergebnis
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Dickere Jacke anziehenCode-Sprache: CSS (css)
Man kann if auch alleine verwenden
void main() {
bool isRaining = false;
bool isSnowing = true;
if (isRaining) {
print("Regenmantel mitnehmen");
}
}Code-Sprache: Dart (dart)
Oder nur if else schreiben
void main() {
bool isRaining = false;
bool isSnowing = true;
if (isRaining) {
print("Regenmantel mitnehmen");
} else {
print("Cabrio fahren");
}
}Code-Sprache: Dart (dart)
II. if-case Musterabgleich-Verzweigung (ab Dart 3.0)
- Passt das Muster, werden Variablen per Destrukturierung an den aktuellen Gültigkeitsbereich gebunden.
- Schlägt der Abgleich fehl, springt der Code zu else. Mit
when-Guard lassen sich zusätzliche boolesche Prüfungen ergänzen. - Geeignet nur für ein Wert, ein Muster. Nutze switch bei mehreren zu prüfenden Mustern.
void main() {
final pair = [100, 220];
// Passt zu einer Liste mit zwei Ganzzahlen
if (pair case [int x, int y]) {
print("Koordinate: $x,$y");
} else {
throw FormatException("Ungültige Koordinate");
}
}
Ausgabeergebnis
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Koordinate: 10,20
2: if-case mit when-Guard
void main() {
final data = [8, 9];
if (data case [int a, int b] when a > 5 && b > 5) {
print("Beide Zahlen sind größer als 5");
} else {
print("Zahlen erfüllen die Bedingung nicht");
}
}
Ausgabeergebnis
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Beide Zahlen sind größer als 5
III. switch-Anweisung
Klassische switch-Anweisung als Statement ohne Rückgabewert
- Cases unterstützen beliebige Muster: Zeichenketten, Konstanten, logisches ODER, Relationsmuster
- Nicht leere Cases brechen automatisch ab, man braucht kein manuelles break; leere Cases führen automatisch zum Fallthrough.
- Zwei Möglichkeiten für manuellen Fallthrough:
continue Labeloder aufeinanderfolgende leere Cases defaultwird ausgeführt, wenn kein Case passt; unterstützt ebenfallswhen-Guards
1: Einfacher Zeichenkettenabgleich
void main() {
String command = "OPEN";
switch (command) {
case "CLOSED":
print("Schließlogik ausführen");
case "PENDING":
print("Wartelogik ausführen");
case "OPEN":
print("Öffnungslogik ausführen");
default:
print("Unbekannter Befehl");
}
}
Ausgabeergebnis
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Öffnungslogik ausführen
2: Fallthrough mit leerem Case + Sprung per continue-Label
String command = "OPEN";
switch (command) {
case "OPEN":
print("Öffnungsvorgang"); // ① Passt zu OPEN und gibt Text aus
continue newCase; // ② Springt direkt zum Label newCase, kehrt nicht zurück
case "DENIED":
case "CLOSED":
print("Schließvorgang");
newCase: // ③ Ziel-Label für den Sprung
case "PENDING":
print("Einheitliche Logik für wartende Vorgänge"); // ④ Wird sofort ausgeführt ohne Prüfung command == "PENDING"
}
Ausgabeergebnis
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Öffnungsvorgang
Einheitliche Logik für wartende Vorgänge
In diesem Beispiel springt
continue newCase;zwar zum Label newCase, aber der nachfolgende case „PENDING“ passt doch gar nicht – warum wirdprint("Einheitliche Logik für wartende Vorgänge");trotzdem ausgeführt?Diese Frage stellen sich viele Leser
continue Label; gleicht den Wert nicht erneut ab, sondern springt direkt zum Anfang des mit dem Label markierten Case-Blocks, überspringt alle Bedingungsprüfungen und führt den Code im Block unverzüglich aus.
3: switch mit when-Guard
void main() {
int score = 88;
switch (score) {
case int s when s >= 90:
print("Sehr gut");
case int s when s >= 60:
print("Bestanden");
default:
print("Nicht bestanden");
}
}
Ausgabe: Bestanden
Zuerst wird der Typ geprüft – der Wert muss eine Ganzzahl sein. Passt der Typ, wird der Wert an Variable s übergeben. Danach läuft der when-Guard als zweite Prüfung; der Case-Code wird nur ausgeführt, wenn s die Bedingung nach when erfüllt. Die beiden int s haben separate Gültigkeitsbereiche und stören sich nicht gegenseitig.
Jedes case int s ist eine eigenständige Musterbindung, deren Gültigkeitsbereich ausschließlich auf den eigenen Case-Block beschränkt ist.
Man kann für beide Cases völlig unterschiedliche Variablennamen verwenden, das Verhalten bleibt identisch.
switch (score) {
case int a when a >= 90:
print("Sehr gut");
case int b when b >= 60:
print("Bestanden");
default:
print("Nicht bestanden");
}
IV. switch-Ausdruck
Syntax ab Dart 3.0 verfügbar, hat einen Rückgabewert und wird häufig zur Variablenzuweisung genutzt
Unterschiede zur switch-Anweisung
- Kein Schlüsselwort
case, Muster und Rückgabeausdruck werden mit=>getrennt - Jeder Zweig muss einen Ausdruck zurückgeben, Zweige werden mit Kommas voneinander abgegrenzt
- Kein impliziter Fallthrough, jeder Zweig ist unabhängig. Passt kein Muster, nutze den Unterstrich
_statt default - Direkt nutzbar bei Zuweisungen, print-Aufrufen, return und allen anderen Ausdruckskontexten
1: Einfacher Zeichenoperatorabgleich (logisches ODER-Muster)
void main() {
const slash = 47, star = 42, comma = 44;
int charCode = 42;
final token = switch (charCode) {
slash || star => "Operator",
comma => "Satzzeichen",
_ => "Ungültiges Zeichen"
};
print(token);
}
Ausgabeergebnis
Operator
Dieses Beispiel definiert Konstanten für die ASCII-Codes von drei Symbolen und prüft anhand der Variable charCode, ob es sich um einen Operator, Satzzeichen oder ungültiges Symbol handelt.
2: switch-Ausdruck mit when-Guard
void main() {
int age = 22;
String level = switch (age) {
int a when a < 18 => "Minderjährig",
int a when a < 30 => "Jugendlicher Erwachsener",
_ => "Erwachsen"
};
print(level);
}
Ausgabeergebnis
Jugendlicher Erwachsener
3: Direkte Nutzung des switch-Ausdrucks im Funktionsreturn
void main() {
print(getDesc(3));
}
String getDesc(int num) => switch (num) {
1 => "Eins",
2 => "Zwei",
_ => "Andere Zahl"
};
Ausgabeergebnis
Andere Zahl
Hinweis: Hier handelt es sich bei switch um einen Ausdruck, getDesc ist eine Pfeilfunktion. Pfeilfunktionen sind eine Dart-eigene Syntax, die es in anderen C-ähnlichen Sprachen nicht gibt.
V. Vollständigkeitsprüfung (Exhaustiveness Checking)
Fehler zur Kompilierzeit, falls für mögliche Eingabewerte kein passender Case existiert – der Compiler zwingt zur Ergänzung fehlender Cases. Versiegelte Klassen (sealed) und Enums unterstützen die Vollständigkeitsprüfung nativ ohne _ oder default als Fallback.
1: Fehler bei unvollständigem nullable Boolean (Kommentiere den Code aus und führe ihn zur Fehleransicht aus)
void main() {
bool? nullableBool = null;
// Auskommentieren des unteren Codes erzeugt einen Kompilierfehler: Fehlender Case für null und kein Fallback durch _/default
/*
switch (nullableBool) {
case true:
print("Wahr");
case false:
print("Falsch");
}
*/
// Korrektur: Hinzufügen eines null-Cases oder Fallback mit _
switch (nullableBool) {
case true:
print("Wahr");
case false:
print("Falsch");
case null:
print("Null-Wert");
}
}
Ausgabeergebnis
Null-Wert
2: Sealed versiegelte Klasse
Algebraischer Datentyp, der eine lückenlose Musterabgleichung erzwingt
import 'dart:math' as math;
// Sealed-Klasse: Unterklassen dürfen nur in dieser Datei definiert werden
sealed class Shape {}
// Unterklasse Quadrat: Seitenlänge
class Square implements Shape {
final double length;
Square(this.length);
}
//Unterklasse Kreis: Radius
class Circle implements Shape {
final double radius;
Circle(this.radius);
}
// Pfeilfunktion, die per switch-Abgleich auf die übergebene Unterklasse die Fläche berechnet
double calculateArea(Shape shape) => switch (shape) {
Square(length: var l) => l * l,
Circle(radius: var r) => math.pi * r * r
// Hinzufügen einer neuen Unterklasse von Shape löst direkt einen Kompilierfehler aus, der auf fehlenden Case hinweist
};
void main() {
final Shape circle = Circle(5);
print(calculateArea(circle));
final Shape square = Square(4);
print(calculateArea(square));
}
Ausgabeergebnis
78.53981633974483
16.0
3: Lückenloser Abgleich mit Enum
Kein Fallback-Unterstrich _ erforderlich
void main() {
final Animal animal = Animal.cat;
String name = switch (animal) {
Animal.dog => "Hund",
Animal.cat => "Katze"
};
print(name);
}
enum Animal { dog, cat }
Ausgabe: Katze
Enums haben einen fest begrenzten Wertebereich, es können keine unbekannten Werte auftauchen – also braucht man keinen Fallback-Zweig.
VI. when-Guards
Vollständig unterstützt bei if-case, switch-Anweisungen und switch-Ausdrücken
Aufgabe von when: Zusätzliche boolesche Prüfung nach erfolgreichem Musterabgleich. Ist der Guard false, geht der Code zum nächsten Zweig, der switch-Block wird nicht verlassen.
1. if-case + when
void main() {
List<int> arr = [10, 20];
if (arr case [int x, int y] when x + y > 20) {
print("Summe der beiden Zahlen ist größer als 20");
}
}
Summe der beiden Zahlen ist größer als 20
Zuerst wird geprüft, ob es sich um eine Liste mit zwei Ganzzahlen handelt; passt das Muster, prüft when ob ihre Summe über 20 liegt.
2. switch-Anweisung + when
void main() {
int num = 15;
switch(num) {
case int n when n % 2 == 0:
print("Gerade Zahl");
case int n when n % 2 != 0:
print("Ungerade Zahl");
}
}
Ausgabe: Ungerade Zahl
Zuerst wird der Typ als Ganzzahl bestätigt, danach läuft die Bedingung im when.
3. switch-Ausdruck + when
void main() {
int num = 15;
String res = switch(num) {
int n when n % 2 == 0 => "Gerade Zahl",
_ => "Ungerade Zahl"
};
print(res);
}