Patterns können erst ab Dart-Version ≥ 3.0 verwendet werden
I. Kernaufgaben von Pattern
Pattern ist eine eigenständige Syntaxkategorie in Dart (gleichrangig mit Anweisungen und Ausdrücken), die die Struktur von Werten beschreibt. Es gibt zwei zentrale Funktionen, die gleichzeitig nutzbar sind: Abgleich (Match) und Dekonstruktion (Destructure).
- Abgleich Match:Prüfen, ob ein Wert der erwarteten Struktur entspricht
- Ist es eine festgelegte Konstante?
- Passt es zu einem bestimmten Typ?
- Hat es eine definierte Struktur (Liste/Objekt/Map/Record)?
- Erfüllt es eine Zusatzbedingung?
- Dekonstruktion Destructure:Bei erfolgreichem Abgleich werden interne Felder und Elemente schnell extrahiert und an Variablen gebunden
1. Beispiel für Konstantenabgleich
void main() {
int number = 1;
switch (number) {
case 1:
print('one'); // Konstanten-Pattern prüft number == 1
default:
print('anderer Wert');
}
}Code-Sprache: Dart (dart)
Ausgabeergebnis
one
2. Geschachtelter Unterpattern-Abgleich
Patterns unterstützen verschachtelte Unterpattern, um interne Strukturen schrittweise zu prüfen
void main() {
const a = 'a';
const b = 'b';
var obj = [ 'a', 'b'];
switch (obj) {
case [a, b]:
print('$a, $b');
default:
print('Kein Treffer');
}
}Code-Sprache: Dart (dart)
Ausgabeergebnis
a, b
3. Einfaches Dekonstruktionsbeispiel
var numList = [1, 2, 3];
// List-Pattern dekonstruiert Listenelemente und bindet an neue Variablen
var [x, y, z] = numList;
print(x + y + z); // 6 x = 1, y = 2, z = 3Code-Sprache: PHP (php)
4. Verschachtelter Pattern-Abgleich + Dekonstruktion
void main() {
var list = ['b', 99];
switch (list) {
// Logisches ODER-Pattern: Erstes Element ist a oder b, zweites an Variable c binden
case ['a' || 'b', var c]:
print(c); // 99
}
}Code-Sprache: Dart (dart)
II. Häufig genutzte Pattern-Beispiele
1. Lokale Variablendeklaration
Zur dekonstruierenden Zuweisung, erstellt mehrere Variablen auf einmal
// Dekonstruktion mit verschachteltem Record + List-Pattern
var (str, [n1, n2]) = ('text', [10, 20]);
print(str); //text
print(n1 + n2); //30Code-Sprache: Dart (dart)
2. Neuzuweisung vorhandener Variablen (Wertaustausch ohne Hilfsvariable)
var (a, b) = ("links", "rechts");
(b, a) = (a, b); // Werte zweier Variablen tauschen
print('$a $b'); // rechts linksCode-Sprache: Dart (dart)
3. switch /if-case Verzweigungen (häufigster Einsatz, when-Wächterklausel)
Jedes case enthält widerlegbare Patterns: Bei fehlendem Abgleich wird das nächste case geprüft
Einfaches Mehrtyp-Case
void testSwitch(dynamic obj) {
switch (obj) {
case 1:
print('Zahl 1');
case >= 10 && <= 20:
print('Zahl zwischen 10 und 20');
case (var a, var b):
print('Record: $a,$b');
default:
print('Kein passender Fall');
}
}Code-Sprache: Dart (dart)
Logisches ODER-Pattern: Gemeinsame Logik für mehrere Fälle
enum Color { red, yellow, blue, green }
void main() {
Color color = Color.red;
bool isPrimary = switch (color) {
Color.red || Color.yellow || Color.blue => true,
_ => false,
};
print(isPrimary); // true
}
Code-Sprache: PHP (php)
when-Wächterklausel (Zusatzfilter nach erfolgreichem Patternabgleich)
sealed class Shape {}
class Square { final double size; Square(this.size); }
class Circle { final double size; Circle(this.size); }
void checkShape(Shape shape) {
switch (shape) {
// Gleichzeitiger Abgleich von Square und Circle mit Zusatzbedingung size>0
case Square(size: var s) || Circle(size: var s) when s > 0:
print('Gültige symmetrische Figur');
default:
print('Ungültige Figur');
}
}Code-Sprache: Dart (dart)
Unterschied zwischen when und normalem if
void compareWhen((int, int) pair) {
switch (pair) {
case (int a, int b):
if (a > b) print('Erster Wert größer');
// Bei fehlender if-Bedingung wird der gesamte switch abgebrochen, nachfolgende cases laufen nicht
case (int a, int b) when a > b:
print('【when-Wächter】Erster Wert größer');
// Bei fehlender when-Bedingung wird nur dieses case übersprungen, nächstes case wird geprüft
case (int a, int b):
print('Erster Wert kleiner oder gleich');
}
}
void main() {
print("===== Test (5, 2) a > b =====");
compareWhen((5, 2));
print("\n===== Test (2, 5) a < b =====");
compareWhen((2, 5));
}Code-Sprache: Dart (dart)
4. for /for-in Schleifen (Dekonstruktion von MapEntry besonders praktisch)
void main() {
Map<String, int> hist = {'a': 23, 'b': 100};
// Volle Schreibweise
for (var MapEntry(key: key, value: count) in hist.entries) {
print('$key : $count');
}
// Kurzschreibweise: key:key wird zu :key vereinfacht
for (var MapEntry(:key, value: count) in hist.entries) {
print('$key : $count');
}
}Code-Sprache: Dart (dart)
Ausgabeergebnis
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
a : 23
b : 100
a : 23
b : 100
Code-Sprache: CSS (css)
III. Praktische Anwendungsfälle von Pattern
1: Mehrere Rückgabewerte einer Funktion (Record-Dekonstruktion)
Herkömmliche Schreibweise (umständlich)
(String, int) userInfo() => ("Lily", 13);
void main() {
var info = userInfo();
var name = info.$1;
var age = info.$2;
}
Code-Sprache: Dart (dart)
Vereinfachte Dekonstruktion per Pattern
var (name, age) = userInfo();
// Dekonstruktion von Records mit benannten Feldern
final (:name, :age) = getData(); // Rückgabewert (name: "Doug", age:25)Code-Sprache: Dart (dart)
Konkretes Beispiel
(String, int) userInfo() => ("Lily", 18);
({String name, int age}) getData() => (name: "Doug", age: 25);
void main() {
{
var (name, age) = userInfo();
print("Name: $name, Alter: $age");
}
// Interne name/age-Variablen kollidieren nicht mit den oberen
{
final (:name, :age) = getData();
print("Name: $name, Alter: $age");
}
}Code-Sprache: Dart (dart)
2: Dekonstruktion von Klasseninstanzen (Objekt-Pattern)
class Foo {
final String one;
final int two;
Foo({required this.one, required this.two});
}
void main() {
final Foo myFoo = Foo(one: "test", two: 66);
var Foo(:one, :two) = myFoo;
print('$one $two'); //test 66
}Code-Sprache: Dart (dart)
3: Algebraische Datentypen (Sealed-Klassen + Berechnung per switch-Verzweigung)
Gesammelte Verarbeitung zusammengehöriger Unterklassen ohne verstreute Instanzmethoden
import 'dart:math';
sealed class Shape {}
class Square implements Shape { final double length; Square(this.length); }
class Circle implements Shape { final double radius; Circle(this.radius); }
double calculateArea(Shape shape) => switch (shape) {
Square(length: var l) => l * l,
Circle(radius: var r) => pi * r * r,
};
Code-Sprache: Dart (dart)
Vollständiges Beispiel
import 'dart:math';
// Versiegelte Oberklasse, Unterklassen nur in dieser Datei definierbar
sealed class Shape {}
// Unterklasse Quadrat
class Square implements Shape {
final double length;
Square(this.length);
}
// Unterklasse Kreis
class Circle implements Shape {
final double radius;
Circle(this.radius);
}
// Einheitliche Flächenberechnung mit switch-Ausdruck + Objekt-Pattern
double calculateArea(Shape shape) => switch (shape) {
// Treffer auf Square, extrahiere length in Variable l
Square(length: var l) => l * l,
// Treffer auf Circle, extrahiere radius in Variable r
Circle(radius: var r) => pi * r * r,
};
void main() {
// Figur-Instanzen erstellen
Shape square = Square(5);
Shape circle = Circle(3);
// Flächen berechnen
double squareArea = calculateArea(square);
double circleArea = calculateArea(circle);
print("Quadratfläche: $squareArea"); // 25.0
print("Kreisfläche: ${circleArea.toStringAsFixed(2)}"); // 28.27
}Code-Sprache: Dart (dart)
Ausgabeergebnis
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Quadratfläche: 25.0
Kreisfläche: 28.27Code-Sprache: CSS (css)
4: JSON-Datenprüfung und Dekonstruktion (starke Vereinfachung verschachtelter Prüfungen)
(Ohne Pattern) Mehrere verschachtelte Typabfragen erzeugen langen Code
void oldCheck(Map data) {
if (data is Map<String, Object?> && data.containsKey('user')) {
var user = data['user'];
if (user is List && user.length == 2) {
String name = user[0] as String;
int age = user[1] as int;
print('$name $age');
}
}
}Code-Sprache: Dart (dart)
if-case-Pattern: Eine Zeile für Strukturprüfung + Typvalidierung + Variablenbindung
void newCheck(Map data) {
if (data case {'user': [String name, int age]}) {
print('Nutzer $name, Alter $age');
}
}Code-Sprache: Dart (dart)
Dieses Pattern prüft gleichzeitig folgende Punkte:
- data ist eine Map und nicht null
- Der Schlüssel „user“ existiert
- Der Wert zu user ist eine Liste mit zwei Elementen
- Erstes Element String, zweites Element int
- Automatische Bindung der lokalen Variablen name und age
Praktisches Anwendungsbeispiel
void main() {
// 1. Gültige JSON-Struktur: Treffer
final validJson = {
'user': ['Lily', 13]
};
newCheck(validJson); // Ausgabe: Nutzer Lily, Alter 13
// 2. Typunverträglichkeit in Liste: Alter als String → kein Treffer
final wrongTypeJson = {
'user': ['Tom', '16']
};
newCheck(wrongTypeJson); // Keine Ausgabe
// 3. Unvollständige user-Liste: Kein Alter → kein Treffer
final shortJson = {
'user': ['Jack']
};
newCheck(shortJson); // Keine Ausgabe
// 4. Schlüssel „user“ fehlt → kein Treffer
final noUserJson = {
'info': ['Bob', 20]
};
newCheck(noUserJson); // Keine Ausgabe
}
// Einstufige Struktur-/Typ-Prüfung & Dekonstruktion mit Map+List-if-case-Pattern
void newCheck(Map data) {
if (data case {'user': [String name, int age]}) {
print('Nutzer $name, Alter $age');
} else {
print('Ungültiges Datenformat');
}
}Code-Sprache: PHP (php)
Pattern-basierter Datenabgleich