Сопоставление с образцом в Swift
Что такое pattern matching
Сопоставление с образцом — способ проверить значение и одновременно извлечь из него части: связать переменные, сравнить с константой, отфильтровать диапазон. В Swift это не отдельный оператор, а поведение switch, if, guard, for-in и присваивания.
Главная польза для прикладного кода:
- меньше вложенных
ifи принудительных!; - компилятор требует исчерпывающие ветки для enum и многих
switch; - единый стиль для опционалов и кортежей и перечислений.
Базовый switch уже разобран в управляющих конструкциях; здесь — расширенные приёмы.
switch без провала между case
В Swift нет неявного fallthrough между case (если не указан fallthrough явно). Каждый case завершается сам по себе — это убирает класс ошибок из C/Java.
Исчерпывающность: для enum без default компилятор проверяет, что обработаны все случаи. При добавлении нового case в enum проект не соберётся, пока вы не обновите switch — защита при эволюции API.
enum Status {
case idle, loading, ready, failed
}
func label(for status: Status) -> String {
switch status {
case .idle: return "Ожидание"
case .loading: return "Загрузка"
case .ready: return "Готово"
case .failed: return "Ошибка"
}
}
Связка значений и where
В case можно привязать части значения к локальным константам:
let point = (x: 3, y: 4)
switch point {
case (0, 0):
print("начало координат")
case let (x, 0):
print("на оси X: \(x)")
case let (0, y):
print("на оси Y: \(y)")
case let (x, y) where x == y:
print("диагональ (\(x), \(y))")
default:
print("обычная точка")
}
where добавляет произвольное условие к уже сопоставленному шаблону.
Enum с associated values
Перечисление может нести данные в каждом случае — удобная модель «результат операции»:
enum LoadState {
case idle
case loading(progress: Double)
case loaded(data: Data)
case failed(message: String)
}
func describe(_ state: LoadState) -> String {
switch state {
case .idle:
return "нет данных"
case .loading(let progress):
return String(format: "%.0f%%", progress * 100)
case .loaded(let data):
return "получено \(data.count) байт"
case .failed(let message):
return message
}
}
Один switch заменяет цепочку if let + проверок типа.
Опционал как enum
Optional — это enum с .none и .some(Wrapped). Поэтому к опционалам применимы те же приёмы.
if let / guard let
Самый частый паттерн — распаковка с узкой областью видимости (if let) или ранний выход (guard let). См. типы данных.
if case let — один случай без полного switch
Когда интересен один вариант:
let response: LoadState = .loaded(data: Data())
if case .loaded(let data) = response {
process(data)
}
Аналог «если статус именно loaded — достать data».
guard case let
Тот же смысл с ранним выходом:
func requireData(from state: LoadState) throws -> Data {
guard case .loaded(let data) = state else {
throw AppError.notReady
}
return data
}
switch по опционалу
let code: Int? = 404
switch code {
case .none:
print("код не задан")
case .some(200):
print("OK")
case .some(let c) where c >= 400:
print("ошибка \(c)")
default:
print("другой код")
}
На практике для опционалов чаще if let / ?? / ?.; switch уместен, когда вариантов много.
Сопоставление в цикле for-in
Фильтрация с распаковкой:
let states: [LoadState] = [.idle, .loading(progress: 0.5), .failed(message: "timeout")]
for case .loading(let p) in states {
print("прогресс \(p)")
}
Обрабатываются только элементы, подходящие под шаблон.
Result и цепочка ошибок
Result<Success, Failure> — enum для успеха/неудачи. Его разбирают тем же switch:
func handle(_ result: Result<User, NetworkError>) {
switch result {
case .success(let user):
showProfile(user)
case .failure(let error):
showAlert(error.localizedDescription)
}
}
Связка с обработкой ошибок: throws + do/catch для исключений, Result — для явного значения в типе возврата.
Когда что выбирать
| Задача | Инструмент |
|---|---|
| Все варианты enum | switch без default |
| Один конкретный case | if case let / guard case let |
| Есть / нет значения | if let, guard let, ?? |
| Фильтр в коллекции | for case, compactMap |
| Ошибка как значение | Result + switch |
Типичные ошибки
defaultтам, где enum фиксирован — скрывает забытый новыйcaseпри рефакторинге.- Принудительный
!вместо паттерна — краш вместо исчерпывающей ветки. - Слишком общий
case let x— теряется смысл; лучше именованные associated values. - Дублирование логики в
if caseиswitch— вынести в одну функцию сswitch.
Связанные материалы
См. также
Другие статьи этого же раздела в боковом меню (как на странице «О разделе»). История Swift - эволюция языка от замены Objective-C до современного инструмента разработки в экосистеме Apple. Экосистема приложений на Swift - инструменты, фреймворки и сценарии разработки в среде Apple. Swift — это современный, безопасный и производительный язык программирования общего назначения, разработанный компанией Apple. Набор советов, правил, принципов и обычаев в разработке на этом языке. Интерфейс класса служит контрактом между разработчиком класса и его пользователями. Он определяет, как взаимодействовать с объектом, не раскрывая механизмов работы. Простые приложения на Swift — CLI, Codable, файлы и сеть на Foundation. Основы Swift - базовый синтаксис, стандартные фреймворки и старт разработки в экосистеме Apple. Строки и Character, интерполяция, точка и вызов методов, запятая, опциональная точка с запятой, скобки и соглашения Swift для iOS и macOS. Ключевые слова Swift - справочник по основным конструкциям языка и их практическому применению. Набор функций, которые включены в стандартную библиотеку языка. Типизация, набор правил определения типа данных значений языка. Управляющие конструкции и циклы в Swift - условия, итерации и безопасное управление потоком выполнения.История языка Swift
Экосистема приложений на Swift
Что требуется знать перед началом изучения языка программирования Swift
Рекомендации по разработке на Swift
Объектно-ориентированное программирование в Swift
Простые приложения на Swift
Основы языка Swift
Синтаксис и пунктуация в Swift
Ключевые слова языка Swift
Встроенные функции и методы Swift
Типы данных и объявление переменных
Управляющие конструкции и циклы в Swift