Pattern Matching (Mustervergleich) ist ein fundamentales Merkmal von Swift, das den Code sicherer und sauberer macht. Historisch gesehen hat sich das Pattern Matching als ein Mittel zur ausdrucksstärkeren und sichereren Handhabung von Enums, insbesondere mit Associated Values, entwickelt. Im Gegensatz zu anderen Sprachen ermöglicht Swift das Entpacken von verschachtelten Werten direkt in den Ausdrücken if, guard und switch.
Problem: Bei nicht-standardmäßigen Enums, insbesondere mit verschachtelten Associated Values, kann man leicht Fehler in der Struktur der Cases machen oder die Einschränkungen des Haupt-Switch unterschätzen. Oft ist auch der Unterschied zwischen der Verwendung von if case, guard case und klassischem switch nicht offensichtlich.
Lösung: Verschiedene Ansätze für Pattern Matching je nach Szenario anwenden und bei komplexen verschachtelten Strukturen die Namen explizit angeben und where verwenden.
Beispielcode:
enum NetworkState { case success(User) case failure(Error, code: Int) case loading(progress: Double) } let state = NetworkState.failure(SomeError(), code: 401) if case let .failure(error, code) = state, code == 401 { print("Unauthorized: \(error)") } guard case .success(let user) = state else { return } print(user) switch state { case .success(let user): print("Willkommen, \(user.name)") case .failure(let error, let code) where code == 404: print("Nicht gefunden: \(error)") case .failure(_, let code): print("Fehler mit Code: \(code)") case .loading(let progress): print("Fortschritt: \(progress)") }
Wesentliche Merkmale:
Was passiert, wenn nicht alle Enum-Cases im Switch angegeben werden?
Kompilierungsfehler (wenn Enum non-optional) oder Warnung/Forderung nach einem Default-Case, wenn nicht alle Abdeckungen berücksichtigt werden. Für Optionals reicht es aus, nur .some und .none anzugeben.
Kann man Pattern Matching mit verschachtelten Enums und Associated Values durchführen?
Ja. Aber die Syntax wird komplexer. Für verschachtelte Werte kann man sofort mehrere Ebenen entpacken:
enum Outer { case inner(Inner) } enum Inner { case item(id: Int) } let e = Outer.inner(.item(id: 5)) if case let .inner(.item(id)) = e { print(id) }
Was ist der Unterschied zwischen guard case und if case beim Mustervergleich?
guard case prüft die Bedingung und führt den Exit-Block (return, throw, break) bei Misserfolg aus. Wird normalerweise für Anforderungen verwendet: wenn es nicht übereinstimmt, aussteigen.
if case ist eine Konstruktion, die für einzeilige bedingte Handler ohne Funktionsausstieg geeignet ist.
Ein Entwickler verwendet switch für ein Enum mit mehreren Cases, deckt aber neuen Case nicht ab. Der Code kompiliert, aber das neue Szenario wird nicht bearbeitet und die Anwendung stürzt zur Laufzeit ab.
Vorteile:
Nachteile:
Ein Entwickler deckt alle Cases explizit ab, verwendet where für lokale Filter und entpackt verschachtelte Werte über verschachteltes let.
Vorteile:
Nachteile: