Pattern matching (сопоставление с образцом) — фундаментальная особенность Swift, делающая код безопаснее и чище. Исторически pattern matching развивался как средство более выразительной и безопасной работы с enum, особенно с associated values. В отличие от других языков, Swift позволяет распаковывать вложенные значения прямо в выражениях if, guard, switch.
Проблема: для нестандартных enum, особенно с вложенными associated values, легко ошибиться в структуре case либо недооценить ограничения главного switch. Также часто неочевидна разница между использованием if case, guard case и классического switch.
Решение: применять разные подходы к pattern matching в зависимости от сценария, а при сложных вложенных структурах — явно указывать имена и использовать where.
Пример кода:
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("Welcome, \(user.name)") case .failure(let error, let code) where code == 404: print("Not Found: \(error)") case .failure(_, let code): print("Failure with code: \(code)") case .loading(let progress): print("Progress: \(progress)") }
Ключевые особенности:
Что будет, если не указать все case enum в switch?
Ошибка компиляции (если enum non-optional) или warning/требование default case, если не все покрытия учтены. Для Optionals достаточно указать только .some и .none.
Можно ли делать pattern matching с вложенными enum и associated values?
Да. Но синтаксис усложняется. Для вложенных значений можно сразу распаковать несколько уровней:
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) }
Чем отличается guard case от if case при сопоставлении с образцом?
guard case проверяет условие и выполняет exit-блок (return, throw, break) при провале. Обычно используется для требований: если не совпало, выйти.
if case — конструкция, подходящая для однострочных условных обработчиков без выхода из функции.
Разработчик использует switch для enum с несколькими case, но не покрывает новый case. Код компилируется, но новый сценарий не обрабатывается и приложение падает в рантайме.
Плюсы:
Минусы:
Разработчик явно покрывает все case, использует where для локальных фильтров, распаковывает вложенные значения через вложенный let.
Плюсы:
Минусы: