Определите, какую ветку выполнит Swift после fallthrough при таком значении x.
let x = 1
switch x {
case 1:
print("one")
fallthrough
case 2:
print("two")
default:
print("other")
}
Программа напечатает one, затем two. После fallthrough Swift без повторной проверки передаёт управление непосредственно в тело следующего case.
fallthrough действует только для текущего switch и не означает обычное продолжение выполнения с повторным сопоставлением значения. Следующая ветка выполняется даже в ситуации, когда её шаблон не соответствовал бы исходному значению.
В конструкциях switch во многих языках переход к следующей ветке происходит неявно, что часто приводит к ошибкам из-за случайно пропущенного break. Swift выбрал более безопасную модель: после выполнения подходящей ветки switch завершается автоматически.
fallthrough оставлен как явный механизм для редких случаев, когда разработчик намеренно хочет продолжить выполнение следующей ветки. Такое намерение видно непосредственно в коде и не зависит от неявного поведения.
В примере значение x соответствует case 1. После печати one выполнение обычно завершило бы switch, однако fallthrough изменяет этот поток управления.
Основной риск состоит в неверном предположении, что Swift сначала проверит case 2, а затем решит, выполнять ли его тело. На самом деле проверка следующего шаблона пропускается, поэтому case 2 выполняется безусловно после перехода.
Сначала Swift сопоставляет x с ветками switch и выбирает case 1. Выполняется его тело: печатается one. Затем fallthrough передаёт управление телу непосредственно следующей ветки — case 2.
Условие case 2 повторно не проверяется. Поэтому тело второй ветки выполнится даже при x == 1; аналогично, при наличии в следующей ветке where её условие не будет использоваться для принятия решения о переходе.
После тела case 2 выполнение покидает switch, если там нет нового явного fallthrough. Использовать fallthrough в последней ветке нельзя, поскольку переходить уже некуда.
Для обычного объединения нескольких значений лучше записать несколько шаблонов через запятую:
Такой вариант выражает классификацию значений и не создаёт искусственного перехода между телами веток. fallthrough уместен только тогда, когда требуется именно последовательное выполнение логики нескольких веток.
Представим обработчик протокола, где один режим должен выполнить собственную подготовку, затем общую логику следующего режима. Разработчик может использовать fallthrough, но это связывает ветки порядком их расположения: перестановка case способна изменить поведение.
Другой вариант — вынести общую логику в отдельную функцию. Это повышает явность и упрощает тестирование, но может добавить небольшую структурную обёртку. Третий вариант — объединить шаблоны, однако он подходит только при одинаковой логике веток и не сохраняет отдельную подготовку.
Предпочтительное решение — отдельная функция для общей операции, а fallthrough применять лишь при действительно последовательной модели перехода. В результате изменение порядка веток меньше влияет на поведение, а намерение кода проще проверить по тестам.
case после fallthrough?Нет. fallthrough сразу передаёт управление следующему телу ветки. Его нельзя рассматривать как повторный запуск механизма сопоставления switch.
fallthrough для перехода через несколько веток?Нет, он переходит только в непосредственно следующую ветку. Чтобы пройти дальше, тело следующей ветки должно само содержать fallthrough; это обычно ухудшает читаемость и требует особенно осторожного контроля порядка case.
fallthrough отличается от объединения шаблонов через запятую?При case 1, 2 оба значения выбирают одно и то же тело после обычного сопоставления. При fallthrough уже выбранная ветка продолжает выполнение в теле следующей, даже если её шаблон не соответствует значению. Поэтому объединение выражает общую классификацию, а fallthrough — намеренную последовательность действий.