Как switch по Optional можно сделать исчерпывающим без default, указав только случаи наличия и отсутствия значения?
Optional имеет ровно два внешних состояния: .some со значением и .none без значения. Поэтому switch становится исчерпывающим, если он явно сопоставляет оба состояния — например, через шаблон наличия значения и nil.
Компилятор проверяет полноту именно внешнего Optional. Если его значение само является Optional, внутренний уровень нужно разбирать отдельно.
Optional решает проблему представления отсутствующего значения без использования специального значения вроде пустой строки, нуля или «магического» объекта. Информация о возможном отсутствии становится частью типа и учитывается компилятором.
В Swift Optional концептуально и фактически представлен перечислением с двумя случаями: .some(Wrapped) и .none. Благодаря этому к нему применяются обычные правила сопоставления с шаблонами и проверки исчерпывающих ветвей switch.
Использование default формально закрывает все неописанные случаи, но скрывает структуру Optional. Такой код сложнее проверять: из него не всегда видно, что обработаны именно наличие значения и nil.
Особенно важно различать уровни вложенности. Для типа Int?? внешний .none означает отсутствие внешнего значения, тогда как внешний .some, содержащий внутренний .none, означает, что внешнее значение присутствует, но внутри него находится nil.
Для обычного T? достаточно сопоставить два внешних состояния:
Шаблон let number? соответствует .some и извлекает wrapped-значение в number типа Int. Шаблон nil соответствует .none. Поскольку других внешних состояний у Int? нет, default не требуется.
Вместо let number? можно явно написать шаблон case .some(let number). Это то же сопоставление с case .some, только в более явной форме. Ветка case .none эквивалентна case nil.
Для вложенного Optional исчерпывающий switch по внешнему уровню всё ещё может иметь только две ветви, но одна из них может содержать внутренний Optional. Чтобы различить все состояния T??, потребуется дополнительно разобрать значение внутри внешнего .some.
default допустим, когда намеренно требуется одинаковая обработка всех остальных случаев или код должен быть устойчив к расширению перечисления. Для Optional он обычно менее выразителен: явные .some и .none документируют намерение и позволяют компилятору контролировать полноту разбора.
Сервис может вернуть String? с названием пользователя. Возможны два результата: имя присутствует или поле отсутствует. Вариант с default обработает отсутствие значения, но не показывает явно, что именно ожидается от типа.
Можно использовать if let, если нужна простая последовательность «есть значение — иначе». Можно применить switch с case let name? и case nil, если ветви содержат разную бизнес-логику или нужно явно зафиксировать оба состояния.
Принудительное извлечение через ! короче, но при nil завершит выполнение аварийно. Выбранный switch безопасен, явно разделяет сценарии и позволяет компилятору проверить, что внешний Optional полностью разобран.
Что произойдёт, если в switch указать только шаблон наличия значения и default?
Такой switch будет корректным: шаблон наличия значения обработает .some, а default поймает .none. Однако default скрывает факт обработки именно .none. Если цель — показать полную модель Optional, лучше записать вторую ветвь явно как nil или .none.
Почему case nil не всегда означает отсутствие значения на всех уровнях вложенного Optional?
case nil сопоставляется с внешним .none. Для Int?? значение, содержащее внутренний nil, имеет форму внешнего .some(.none), поэтому внешняя ветвь case nil его не поймает. Сначала нужно сопоставить внешний .some, а затем разобрать вложенный Int?.
Можно ли считать if let альтернативой проверке исчерпывающего switch?
if let безопасно проверяет только наличие значения и предоставляет ветвь else для всех остальных случаев, то есть для .none. Но он не выражает структуру через явные case и не используется для проверки исчерпывающего сопоставления нескольких вариантов. switch предпочтительнее, когда важно явно перечислить состояния или извлечь значения разными шаблонами.