switch сравнивает одно значение со списком вариантов и выполняет первое совпадение. В отличие от C, Java и JavaScript, ветка case в Go не проваливается в следующую, поэтому забыть break невозможно.
Варианты проверяются сверху вниз, и выполняется только первый совпавший. default выполняется, если ничего не совпало; он необязателен и может стоять в любом месте списка, но по соглашению его ставят последним.
Несколько значений в одном case
case "sat", "sun": совпадает с любым из значений. Так Go выражает то, что в C делают стопкой пустых case. Подходит любой сравнимый тип: строки, числа, руны, булевы значения, указатели и именованные типы, например перечисления:
Два case с одинаковым константным значением дают ошибку компиляции:
./main.go:10:7: duplicate case 1 (constant of type int) in expression switch
./main.go:8:7: previous case
switch без условия
Уберите выражение, и каждый case превратится в булеву проверку. Это более чистая форма длинной цепочки if/else if:
switch { это сокращение для switch true {. Побеждает первый истинный case, поэтому порядок важен: до bmi < 25 дело доходит, только если bmi < 18.5 оказалось ложным, так что каждый case может считать, что все варианты выше не сработали.
switch с инструкцией инициализации
Как и if, switch может начинаться с короткой инструкции. Объявленные в ней переменные видны только внутри switch:
Инструкцию инициализации можно сочетать и со switch без выражения: switch n := len(items); { case n == 0: ... }.
fallthrough
Если продолжить выполнение в следующем case всё же нужно, напишите fallthrough последней инструкцией ветки. Управление перейдёт в тело следующего case без вычисления его условия:
Уровень 2 печатает write, а затем read, накапливая права сверху вниз. Условия последующих case не проверяются: после fallthrough из case 2 выполняется case 1, хотя level равен 2.
Правила для fallthrough:
- Это должна быть последняя инструкция в ветке.
- Он не может стоять в последнем case:
cannot fallthrough final case in switch. - В type switch он запрещён.
На практике fallthrough в коде на Go встречается редко. Несколько значений в одном case покрывают обычную потребность, а явные вызовы функций обычно понятнее цепочки проваливаний.
break в switch
break внутри case выходит из switch. Ветки заканчиваются сами, поэтому он нужен, только чтобы покинуть ветку досрочно. Ловушка возникает, когда switch стоит внутри цикла:
Без метки loop оператор break завершит switch, а цикл продолжится до "c". А вот continue всегда относится к охватывающему циклу, ведь switch не является циклом.
switch по типам
Type switch выбирает ветку по динамическому типу значения интерфейса, используя особую форму v.(type):
В case с одним типом x имеет этот тип (в ветке string работает len(x)). В case с несколькими типами x остаётся интерфейсом. Type switch и утверждение v.(T) подробно разобраны на странице об утверждениях типа.
Чем switch в Go отличается
| Поведение | C, Java, JavaScript | Go |
|---|---|---|
| Проваливание в следующий case | по умолчанию | только через fallthrough |
break в конце каждого case | обязателен | не нужен |
| Несколько значений в case | стопка пустых case | case a, b, c: |
| Значения case | в основном константы | любое выражение, вычисляется сверху вниз |
| Значение switch | целочисленные типы (C) | любой сравнимый тип |
| switch без выражения | нельзя | switch { case cond: } |
Выражения в case не обязаны быть константами. case limit(), max + 1: допустимо; они вычисляются по порядку до первого совпадения, поэтому более поздние выражения могут не выполниться вовсе.
Полнота вариантов
Go не проверяет, что switch по перечислению покрывает все значения. Добавьте default, который логирует, возвращает ошибку или паникует на неожиданных значениях, или используйте линтер exhaustive (входит в golangci-lint), чтобы пропущенные варианты сообщались при сборке.
Часто задаваемые вопросы
Проваливается ли switch в Go в следующий case?
Нет. Ветка case в Go автоматически заканчивается на следующем case; писать break, чтобы её остановить, не нужно. Если нужно продолжить выполнение в теле следующего case, напишите fallthrough последней инструкцией ветки. Переход безусловный, условие следующего case не проверяется.
Как проверить несколько значений в одном case в Go?
Перечислите их через запятую: case "sat", "sun":. Ветка выполнится, если значение switch равно любому из них. Это заменяет пустые проваливающиеся case, которые в C или Java ставят друг над другом.
Что такое switch без условия в Go?
switch { case x < 0: ...; case x == 0: ...; default: ... }. Если после switch нет выражения, каждый case является булевым условием, и выполняется первый истинный. Это идиоматичная замена длинной цепочки if/else if.
Что делает break внутри switch в Go?
Завершает switch, а не охватывающий цикл for. Нужен он редко, ведь ветки заканчиваются сами, но он удивляет тех, кто пишет break внутри switch внутри цикла в надежде выйти из цикла. Для этого используйте break с меткой или return.