cat posts/match-case-pattern-matching.md
match/case: Strukturelles Pattern Matching
match/case ist mehr als ein switch: Mit Literal-, Sequenz-, Mapping- und Class-Patterns zerlegst Du Datenstrukturen, bindest Werte und ergänzt Bedingungen über Guards.
In Teil 3 der Python-Serie
haben wir die Befehle des Spielers mit einer längeren
if-elif-else-Kette verarbeitet:
if befehl == "norden":
...
elif befehl == "osten":
...
elif befehl == "status":
...
else:
...
Seit Python 3.10 gibt es mit match und case eine weitere Möglichkeit,
unterschiedliche Fälle zu behandeln.
Wer switch aus anderen Programmiersprachen kennt, könnte match zunächst für
Pythons Variante davon halten. Einfache Wertvergleiche sind damit tatsächlich
möglich. Der eigentliche Zweck geht aber deutlich weiter:
Structural Pattern Matching kann Datenstrukturen untersuchen, ihre Form
prüfen und enthaltene Werte direkt an Variablen binden.
Die Grundform
Ein match-Statement besteht aus einem Subject und mehreren Patterns:
match subject:
case pattern_1:
...
case pattern_2:
...
case _:
...
Python wertet das Subject aus und prüft anschließend die case-Blöcke von oben
nach unten. Der erste passende Block wird ausgeführt.
Danach endet das gesamte match-Statement. Anders als bei manchen
switch-Varianten gibt es kein automatisches Fall-through und deshalb auch
kein break nach jedem case.
Ein einfaches Beispiel:
def reagiere(befehl):
match befehl:
case "norden":
return "Du gehst nach Norden."
case "osten":
return "Du gehst nach Osten."
case "ende":
return "Du verlässt das Verlies."
case _:
return "Das verstehe ich nicht."
Die Strings in den ersten drei Cases sind Literal Patterns. Sie passen nur, wenn das Subject denselben Wert besitzt.
Der Unterstrich _ ist ein Wildcard Pattern. Er passt auf jeden Wert und
übernimmt damit die Rolle des abschließenden else.
print(reagiere("norden"))
print(reagiere("tanzen"))
Ausgabe:
Du gehst nach Norden.
Das verstehe ich nicht.
Der Wildcard-Case sollte immer zuletzt stehen. Da er auf alles passt, wären nachfolgende Cases nicht mehr erreichbar.
Mehrere Alternativen mit OR-Patterns
Mehrere Patterns lassen sich mit | verbinden:
def reagiere(befehl):
match befehl:
case "norden" | "sueden" | "osten" | "westen":
return "Du gehst los."
case "ende" | "quit":
return "Du verlässt das Verlies."
case _:
return "Das verstehe ich nicht."
Das | ist innerhalb eines Patterns kein boolesches or, sondern bildet ein
OR-Pattern. Es passt, sobald eine der angegebenen Alternativen passt.
Du kannst den passenden Wert gleichzeitig an einen Namen binden:
def bewege(richtung):
match richtung:
case ("norden" | "sueden" | "osten" | "westen") as ziel:
return f"Du gehst nach {ziel}."
case _:
return "Dort kannst Du nicht hingehen."
Das as bindet den vollständig passenden Wert an ziel.
print(bewege("westen"))
Ausgabe:
Du gehst nach westen.
Bei OR-Patterns müssen alle Alternativen dieselben Namen binden. Diese Variante ist gültig:
match eingabe:
case ["geh", richtung] | ["laufe", richtung]:
print(f"Du gehst nach {richtung}.")
Beide Alternativen binden einen Wert an richtung.
Diese Variante wäre dagegen ungültig:
match eingabe:
case ["geh", richtung] | ["laufe", ziel]:
...
Python könnte nicht garantieren, welcher Name im zugehörigen Block verfügbar ist.
Das erste passende Pattern gewinnt
Wie bei einer if-elif-Kette ist die Reihenfolge entscheidend.
match befehl:
case _:
print("Beliebiger Befehl")
case "ende":
print("Spiel beenden")
Dieser Code ist ungültig. Das Wildcard Pattern passt bereits auf jeden möglichen Wert. Der zweite Case könnte deshalb niemals erreicht werden.
Auch bei spezielleren Patterns gilt: Prüfe besondere Fälle vor allgemeineren Fällen.
match eingabe.split():
case ["nimm"]:
print("Was möchtest Du nehmen?")
case ["nimm", gegenstand]:
print(f"Du nimmst {gegenstand}.")
case ["nimm", *gegenstaende]:
print(f"Du nimmst {', '.join(gegenstaende)}.")
Die drei Patterns behandeln unterschiedliche Formen der Eingabe:
["nimm"]: genau ein Wort["nimm", gegenstand]: genau zwei Wörter["nimm", *gegenstaende]: mindestens ein Wort, alle weiteren werden gesammelt
Die spezielleren Varianten stehen zuerst.
Capture Patterns: Werte an Namen binden
Ein Name innerhalb eines Patterns ist normalerweise kein Vergleich, sondern ein Capture Pattern.
match eingabe.split():
case ["nimm", gegenstand]:
print(f"Du nimmst {gegenstand}.")
Bei der Eingabe
nimm fackel
liefert split() diese Liste:
["nimm", "fackel"]
Das Pattern
["nimm", gegenstand]
bedeutet:
- Das Subject muss eine Sequenz mit genau zwei Elementen sein.
- Das erste Element muss dem Literal
"nimm"entsprechen. - Das zweite Element wird an den Namen
gegenstandgebunden.
Im zugehörigen Block enthält gegenstand deshalb den String "fackel".
Die Bindung bleibt auch nach dem match-Statement erhalten, sofern der
entsprechende Case erfolgreich ausgewählt wurde. Meistens ist es trotzdem
übersichtlicher, den Namen nur innerhalb des Case-Blocks zu verwenden.
Sequence Patterns
Sequence Patterns zerlegen sequenzartige Werte wie Listen und Tupel.
def verarbeite(eingabe):
woerter = eingabe.strip().lower().split()
match woerter:
case []:
return "Sag etwas."
case ["umsehen"] | ["schau"]:
return "Du schaust Dich um."
case ["nimm"]:
return "Was möchtest Du nehmen?"
case ["nimm", gegenstand]:
return f"Du nimmst {gegenstand}."
case ["geh", richtung]:
return f"Du gehst nach {richtung}."
case _:
return "Unbekannter Befehl."
Ein Pattern ohne Stern benötigt genau die angegebene Anzahl von Elementen:
case ["geh", richtung]:
Es passt auf:
["geh", "norden"]
Es passt aber nicht auf:
["geh"]
["geh", "nach", "norden"]
Mehrere Elemente mit * sammeln
Ein Stern sammelt mehrere Elemente in einer Liste:
match eingabe.split():
case ["sage", *woerter]:
print(" ".join(woerter))
Bei
sage öffne das alte tor
enthält woerter:
["öffne", "das", "alte", "tor"]
Das Star-Pattern darf auch in der Mitte stehen:
match daten:
case [erstes, *mitte, letztes]:
print(f"Erstes: {erstes}")
print(f"Mitte: {mitte}")
print(f"Letztes: {letztes}")
Für
[1, 2, 3, 4, 5]
werden folgende Werte gebunden:
erstes = 1
mitte = [2, 3, 4]
letztes = 5
Innerhalb eines Sequence Patterns darf höchstens ein Star-Pattern vorkommen.
Eckige und runde Klammern
Für Sequence Patterns kannst Du eckige oder runde Klammern verwenden:
case [x, y]:
...
case (x, y):
...
Beide Schreibweisen prüfen grundsätzlich auf eine passende Sequenz und nicht speziell auf eine Liste beziehungsweise ein Tupel.
Dieses Pattern:
case [x, y]:
kann deshalb sowohl auf
[10, 20]
als auch auf
(10, 20)
passen.
Strings, bytes und bytearray werden beim Structural Pattern Matching bewusst
nicht als Sequenzen einzelner Elemente behandelt. Ein Pattern wie
case [erstes, zweites]:
zerlegt deshalb nicht automatisch einen zweistelligen String.
Für Textbefehle verwenden wir zunächst .split(), wodurch eine echte Liste
entsteht.
Mapping Patterns
Mit einem Mapping Pattern kannst Du Dictionaries und andere Mapping-Typen untersuchen:
spieler = {
"name": "Karl",
"hp": 75,
"max_hp": 100,
"gold": 50,
}
Ein Pattern kann gezielt einzelne Schlüssel prüfen und ihre Werte binden:
match spieler:
case {"hp": hp}:
print(f"Der Spieler besitzt {hp} Lebenspunkte.")
Das Pattern passt auf jedes Mapping, das den Schlüssel "hp" enthält. Weitere
Einträge stören nicht.
Das ist ein wichtiger Unterschied zu einem Sequence Pattern: Ein Mapping muss nicht exakt dieselben Einträge besitzen, die im Pattern stehen.
Mehrere Schlüssel prüfen
match spieler:
case {"name": name, "hp": hp}:
print(f"{name} besitzt {hp} Lebenspunkte.")
Beide Schlüssel müssen vorhanden sein. Ihre Werte werden an name und hp
gebunden.
Du kannst auch einen konkreten Wert verlangen:
match spieler:
case {"hp": 0}:
print("Game Over.")
case {"hp": hp}:
print(f"Noch {hp} HP.")
Der erste Case passt nur, wenn "hp" tatsächlich den Wert 0 besitzt.
Übrige Einträge mit ** sammeln
Mit **rest kannst Du alle nicht ausdrücklich genannten Einträge in einem neuen
Dictionary sammeln:
match spieler:
case {"name": name, **rest}:
print(f"Name: {name}")
print(f"Übriger State: {rest}")
Für den vorherigen Player State enthält rest:
{
"hp": 75,
"max_hp": 100,
"gold": 50,
}
Anders als beim Erstellen eines Dictionaries ist **_ in einem Mapping Pattern
nicht erlaubt. Nicht benötigte zusätzliche Einträge kannst Du einfach
ignorieren, indem Du gar kein **rest verwendest.
Guards: Zusätzliche Bedingungen
Ein Pattern prüft in erster Linie Form, Typ und enthaltene Werte. Für weitere Bedingungen kannst Du einen Guard ergänzen:
match spieler:
case {"hp": hp} if hp <= 0:
print("Game Over.")
case {"hp": hp} if hp <= 25:
print(f"Dein Zustand ist kritisch: {hp} HP.")
case {"hp": hp}:
print(f"Du besitzt noch {hp} HP.")
Der Guard beginnt mit if und steht zwischen Pattern und Doppelpunkt.
Python geht dabei in zwei Schritten vor:
- Das Pattern muss passen.
- Anschließend muss der Guard
Trueergeben.
Passt das Pattern, aber der Guard ergibt False, prüft Python den nächsten
Case.
Die gebundenen Namen stehen im Guard bereits zur Verfügung:
case {"hp": hp} if hp <= 25:
Zuerst wird der Wert des Schlüssels "hp" an hp gebunden. Danach prüft der
Guard, ob dieser Wert kleiner oder gleich 25 ist.
Bereiche besser mit if prüfen
Für reine Wertebereiche bleibt ein normales if häufig klarer:
if hp <= 0:
print("Game Over.")
elif hp <= 25:
print("Kritisch!")
else:
print("Alles in Ordnung.")
match bietet keinen eigenen Pattern-Typ für Zahlenbereiche. Du könntest einen
Wert zwar über einen Guard prüfen:
match hp:
case wert if wert <= 0:
...
case wert if wert <= 25:
...
Das ist gegenüber der if-Variante aber meist unnötig kompliziert.
Pattern Matching lohnt sich vor allem dann, wenn neben der Bedingung auch die Struktur der Daten geprüft und zerlegt werden soll.
Class Patterns
Class Patterns prüfen, ob das Subject eine Instanz einer bestimmten Klasse ist, und können anschließend Attribute untersuchen.
class Punkt:
def __init__(self, x, y):
self.x = x
self.y = y
Mit Keyword Patterns kannst Du die Attribute direkt ansprechen:
punkt = Punkt(0, 7)
match punkt:
case Punkt(x=0, y=0):
print("Der Punkt liegt im Ursprung.")
case Punkt(x=0, y=y):
print(f"Der Punkt liegt auf der Y-Achse bei {y}.")
case Punkt(x=x, y=0):
print(f"Der Punkt liegt auf der X-Achse bei {x}.")
case Punkt(x=x, y=y):
print(f"Der Punkt liegt bei {x}, {y}.")
Der zweite Case prüft:
- Ist das Subject eine Instanz von
Punkt? - Besitzt das Attribut
xden Wert0? - Falls ja, binde das Attribut
yan den lokalen Nameny.
Die Ausgabe lautet:
Der Punkt liegt auf der Y-Achse bei 7.
Ein Class Pattern erzeugt dabei kein neues Objekt. Die Schreibweise
case Punkt(x=0, y=y):
sieht zwar wie ein Constructor Call aus, beschreibt aber ein Pattern für ein bereits vorhandenes Objekt.
Positionale Class Patterns mit __match_args__
Sollen Attribute positional angegeben werden, benötigt die Klasse
__match_args__:
class Punkt:
__match_args__ = ("x", "y")
def __init__(self, x, y):
self.x = x
self.y = y
Nun sind kürzere Patterns möglich:
match punkt:
case Punkt(0, 0):
print("Ursprung")
case Punkt(0, y):
print(f"Y-Achse bei {y}")
case Punkt(x, 0):
print(f"X-Achse bei {x}")
case Punkt(x, y):
print(f"Punkt bei {x}, {y}")
Die Definition
__match_args__ = ("x", "y")
legt fest, dass
Punkt(0, y)
sinngemäß diesem Keyword Pattern entspricht:
Punkt(x=0, y=y)
Bei selbst geschriebenen Klassen sind Keyword Patterns oft expliziter und leichter verständlich. Positionale Patterns eignen sich besonders für Klassen, deren Attribute eine klare und stabile Reihenfolge besitzen.
Patterns kombinieren
Patterns lassen sich ineinander verschachteln.
Betrachten wir ein Event aus einem Spiel:
event = {
"typ": "schaden",
"quelle": {
"name": "Goblin",
"art": "monster",
},
"wert": 25,
}
Dieses Mapping können wir in einem einzigen Pattern untersuchen:
match event:
case {
"typ": "schaden",
"quelle": {"name": name, "art": "monster"},
"wert": schaden,
}:
print(f"{name} verursacht {schaden} Schaden.")
Das Pattern prüft gleichzeitig:
- Der Event-Typ muss
"schaden"sein. quellemuss ein Mapping sein.- Die Art der Quelle muss
"monster"sein. - Der Name wird an
namegebunden. - Der Schadenswert wird an
schadengebunden.
Ausgabe:
Goblin verursacht 25 Schaden.
Mit einer klassischen if-Abfrage müssten wir die einzelnen Ebenen getrennt
ansprechen:
if (
event["typ"] == "schaden"
and event["quelle"]["art"] == "monster"
):
name = event["quelle"]["name"]
schaden = event["wert"]
Pattern Matching verbindet die Strukturprüfung und das Herauslösen der benötigten Werte.
Die Falle mit nackten Namen
Einer der wichtigsten Unterschiede zu einem klassischen switch betrifft Namen
in Patterns.
Betrachten wir eine vermeintliche Konstante:
ENDE = "ende"
Dieser Code sieht nach einem Vergleich aus:
def reagiere(befehl):
match befehl:
case ENDE:
return "Das Spiel endet."
case ENDE vergleicht aber nicht mit dem vorher definierten Wert "ende".
Ein nackter Name ist ein Capture Pattern. Er bindet jeden beliebigen Wert des
Subjects an den Namen ENDE. Der Case passt deshalb immer.
print(reagiere("norden"))
würde ebenfalls
Das Spiel endet.
zurückgeben.
Fügst Du danach einen weiteren ungeschützten Case ein, meldet Python bereits beim Parsen einen Fehler, weil nach dem irrefutable Capture Pattern nichts mehr erreichbar wäre:
match befehl:
case ENDE:
...
case _:
...
Warum Literale funktionieren
Diese Patterns sind direkte Wertvergleiche:
case "ende":
case 404:
case True:
case False:
case None:
Strings, Zahlen und die besonderen Literale True, False und None werden
nicht als Capture Patterns behandelt.
Benannte Werte müssen gepunktet sein
Ein benannter Wert kann als Value Pattern verwendet werden, wenn der Name mindestens einen Punkt enthält:
class Befehle:
ENDE = "ende"
STATUS = "status"
Nun funktionieren echte Vergleiche:
def reagiere(befehl):
match befehl:
case Befehle.ENDE:
return "Das Spiel endet."
case Befehle.STATUS:
return "Der Status wird angezeigt."
case _:
return "Unbekannter Befehl."
Befehle.ENDE ist ein gepunkteter Name. Python schlägt den zugehörigen Wert
nach und vergleicht ihn mit dem Subject.
Auch Enum Members werden typischerweise so verwendet:
from enum import Enum
class Status(Enum):
AKTIV = 1
BESIEGT = 2
match status:
case Status.AKTIV:
print("Das Spiel läuft.")
case Status.BESIEGT:
print("Game Over.")
Hier ist status allerdings ein Enum Member und nicht lediglich dessen
numerischer Wert.
Ein Guard als Alternative
Du kannst den Vergleich auch über einen Guard ausdrücken:
ENDE = "ende"
match befehl:
case wert if wert == ENDE:
print("Das Spiel endet.")
case _:
print("Unbekannter Befehl.")
Das funktioniert, ist für einen einfachen Wertvergleich aber meist umständlicher als:
if befehl == ENDE:
...
Ein Command Parser für den Dungeon
Im Dungeon können wir match verwenden, um den in Wörter zerlegten Input zu
verarbeiten.
def verarbeite_befehl(eingabe, raum, spieler):
"""Verarbeitet einen Textbefehl und gibt das Ergebnis zurück."""
woerter = eingabe.strip().lower().split()
match woerter:
case []:
return "Bitte gib einen Befehl ein."
case ["ende"] | ["quit"]:
return "ende"
case ["umsehen"] | ["schau"]:
gegenstaende = raum["gegenstaende"]
if gegenstaende:
return "Hier liegt: " + ", ".join(gegenstaende)
return "Hier liegt nichts Brauchbares."
case ["inventar"]:
inventar = spieler["inventar"]
if inventar:
return "Inventar: " + ", ".join(inventar)
return "Dein Inventar ist leer."
case ["status"]:
return (
f"{spieler['name']} | "
f"HP: {spieler['hp']}/{spieler['max_hp']} | "
f"Gold: {spieler['gold']}"
)
case ["nimm"]:
return "Was möchtest Du nehmen?"
case ["nimm", *namen] if namen:
gesucht = " ".join(namen)
for gegenstand in raum["gegenstaende"]:
if gegenstand.lower() == gesucht:
raum["gegenstaende"].remove(gegenstand)
spieler["inventar"].append(gegenstand)
return f"Du nimmst {gegenstand}."
return f"Hier liegt kein Gegenstand namens {gesucht}."
case ["geh", richtung] | [richtung] if richtung in raum["ausgaenge"]:
return raum["ausgaenge"][richtung]
case _:
return "Das verstehe ich nicht."
Der Input
nimm alte fackel
wird durch .split() zu:
["nimm", "alte", "fackel"]
Das Pattern
case ["nimm", *namen] if namen:
bindet
["alte", "fackel"]
an namen.
Anschließend setzt
gesucht = " ".join(namen)
die Wörter wieder zu
alte fackel
zusammen.
Das Bewegungs-Pattern akzeptiert zwei Formen:
case ["geh", richtung] | [richtung] if richtung in raum["ausgaenge"]:
Damit funktionieren sowohl
geh norden
als auch
norden
Der Guard stellt sicher, dass richtung tatsächlich ein Ausgang des aktuellen
Raums ist.
Wichtig: Die Funktion verwendet unterschiedliche Return Values für unterschiedliche Ergebnisse. In einem größeren Programm wäre es sinnvoll, diese Ergebnisse eindeutiger zu strukturieren, beispielsweise über Tupel, Dictionaries oder eigene Klassen. Für das Beispiel reicht die vereinfachte Form.
Wann ist match sinnvoll?
match eignet sich besonders, wenn Du:
- die Form einer Liste oder eines Tupels prüfen möchtest,
- Dictionaries anhand bestimmter Schlüssel untersuchst,
- Werte während der Prüfung an Namen binden möchtest,
- unterschiedliche Klassen oder Objektformen behandelst,
- mehrere verschachtelte Strukturen gleichzeitig prüfen möchtest,
- einen kleinen Parser für strukturierte Befehle oder Events baust.
Ein typischer Anwendungsfall ist:
match nachricht:
case {"typ": "chat", "text": text}:
...
case {"typ": "bewegung", "x": x, "y": y}:
...
case {"typ": "schaden", "wert": wert, "quelle": quelle}:
...
Hier unterscheiden sich die Fälle nicht nur durch einen einzelnen Wert, sondern durch ihre gesamte Struktur.
Wann ist if besser?
Ein normales if bleibt häufig besser für:
- einfache boolesche Bedingungen,
- Zahlenbereiche,
- Vergleiche mit wenigen einzelnen Werten,
- komplexe Bedingungen ohne erkennbare Datenstruktur.
Beispiel:
if hp <= 0:
print("Game Over.")
elif hp <= 25:
print("Kritisch!")
else:
print("Du kannst weiterkämpfen.")
Diese Logik als match mit mehreren Guards zu schreiben, wäre nicht klarer.
Auch dieser einfache Vergleich benötigt kein Pattern Matching:
if befehl == "ende":
spiel_beenden()
match ist kein Ersatz für jedes if. Es ist ein zusätzliches Werkzeug für
Fälle, in denen die Struktur der Daten Teil der Entscheidung ist.
Stolperfallen
-
Einen nackten Namen für eine Konstante halten:
case ENDEvergleicht nicht mit einer Variablen namensENDE, sondern bindet jeden Wert an diesen Namen. Verwende ein Literal, einen gepunkteten Namen oder ein normalesif. -
Den Wildcard-Case zu früh einsetzen:
case _passt auf alles und muss deshalb zuletzt stehen. -
Die Reihenfolge zu allgemein beginnen: Das erste passende Pattern gewinnt. Spezifische Patterns gehören vor allgemeinere Patterns.
-
Sequence Patterns mit exakten Typprüfungen verwechseln:
[x, y]kann auf unterschiedliche Sequenztypen passen. Es prüft nicht ausschließlich auf eine Liste. -
Strings direkt als Sequence Pattern zerlegen wollen: Strings,
bytesundbytearraywerden von Sequence Patterns nicht als Folgen einzelner Elemente behandelt. Nutze bei Textbefehlen beispielsweise.split(). -
Bei einem Mapping exakte Gleichheit erwarten:
{"hp": hp}passt auch auf Dictionaries mit zusätzlichen Schlüsseln. -
Bei OR-Patterns unterschiedliche Namen binden: Alle Alternativen müssen dieselbe Menge an Namen bereitstellen.
-
Class Patterns für Constructor Calls halten:
case Punkt(x=0, y=y)erzeugt kein Objekt, sondern prüft ein vorhandenes Objekt. -
breaknach einem Case schreiben: Nach dem ersten passenden Case endet dasmatch-Statement automatisch. -
matchfür jeden Vergleich verwenden: Einfache Bedingungen und Wertebereiche sind mitifhäufig klarer.
Kompakte Übersicht
| Pattern | Beispiel | Bedeutung |
|---|---|---|
| Literal Pattern | case "ende": |
passt auf einen konkreten Wert |
| Wildcard Pattern | case _: |
passt auf jeden Wert |
| Capture Pattern | case wert: |
bindet das Subject an wert |
| OR-Pattern | case "ja" \| "j": |
passt auf eine der Alternativen |
| AS-Pattern | case ("n" \| "s") as richtung: |
bindet das passende Pattern |
| Sequence Pattern | case ["nimm", ding]: |
prüft und zerlegt eine Sequenz |
| Star Pattern | case [erstes, *rest]: |
sammelt übrige Elemente |
| Mapping Pattern | case {"hp": hp}: |
prüft Schlüssel und bindet Werte |
| Class Pattern | case Punkt(x=0, y=y): |
prüft Klasse und Attribute |
| Guard | case wert if wert > 0: |
ergänzt eine Bedingung |
| Value Pattern | case Status.AKTIV: |
vergleicht mit einem gepunkteten Wert |
Fazit
match und case sind weit mehr als eine alternative Schreibweise für
if-elif-Ketten.
Structural Pattern Matching kann:
- Literale vergleichen,
- Sequenzen zerlegen,
- Dictionaries anhand ihrer Schlüssel untersuchen,
- Attribute von Objekten prüfen,
- Werte direkt an Namen binden,
- Patterns kombinieren,
- zusätzliche Bedingungen über Guards anwenden.
Seine größte Stärke zeigt match nicht beim Vergleich einzelner Strings,
sondern bei strukturierten Daten.
Die wichtigste Regel dabei lautet:
Ein nackter Name in einem Pattern ist eine neue Bindung, kein Zugriff auf eine vorhandene Variable.
Sobald Du diesen Unterschied verstanden hast, wird aus der vermeintlichen
switch-Anweisung ein mächtiges Werkzeug zum Analysieren und Zerlegen von Daten.
0 Kommentare
Noch keine Kommentare. Sei der/die Erste!
Anmelden um einen Kommentar zu hinterlassen.