Перейти к содержимому
Теория · Условия · урок 4 из 7

switch

В холле большого здания висит указатель: «Бухгалтерия — 3 этаж, отдел кадров — 5 этаж, столовая — 1 этаж». Вы не обходите все этажи по очереди, а находите в указателе свою строку и сразу едете на нужный этаж.

Цепочка else if похожа на обход этажей. Когда одну переменную сравнивают с несколькими значениями, цепочка повторяет одно и то же сравнение в каждой ветке. Инструкция switch работает как указатель в холле: вычисляет выражение один раз и выполняет ветку case с таким же значением:

GO
package main

import "fmt"

func main() {
    day := 6
    switch day {
    case 1, 2, 3, 4, 5:
        fmt.Println("workday")
    case 6, 7:
        fmt.Println("weekend") // weekend
    default:
        fmt.Println("no such day")
    }
}

Давайте пройдём по программе:

  1. switch day вычисляет day и получает 6.
  2. case 1, 2, 3, 4, 5: — эти значения не подходят.
  3. case 6, 7: — шестёрка в списке есть, поэтому программа печатает weekend.
  4. default: — до этой ветки дело не доходит.

Ветки case и default

В switch с выражением два вида веток.

case со значениями

Ветка case перечисляет значения, при которых она выполняется. Правила такие:

  • несколько значений одного case перечисляют через запятую: case 6, 7:;
  • значения имеют тот же тип, что и выражение после switch;
  • одно значение не может стоять в двух case: компилятор сообщит duplicate case.

default

Ветка default выполняется, когда не подошёл ни один case. Если её нет, в этом случае не выполняется ничего.

Если функция возвращает значение из веток switch, компилятор требует ветку default или return после switch. Без них он сообщает missing return, даже когда условия покрывают все случаи.

Конец ветки

В разных языках ветка switch заканчивается по-разному. В Go есть два варианта.

Без break

После выполненной ветки switch сразу завершается, поэтому break в конце ветки не нужен. В C всё наоборот: без break выполнение проваливается в следующую ветку.

fallthrough

В Go проваливание включают явно, словом fallthrough в конце ветки:

GO
level := 2
switch level {
case 2:
    fmt.Print("admin ")
    fallthrough
case 1:
    fmt.Println("user") // admin user
}

Разберём, что делает fallthrough:

  • переходит в следующий case, не проверяя его значение, поэтому при level == 2 программа печатает admin user;
  • при level == 1 программа печатает только user: ветка case 2 не выполнялась;
  • fallthrough пишут последней инструкцией ветки, а в последней ветке switch его писать нельзя: переходить некуда.

Нужен fallthrough редко: обычно хватает нескольких значений в одном case.

Этот вопрос часто задают на собеседовании: чем switch в Go отличается от switch в C? Главное в ответе: в Go ветка не проваливается в следующую сама, break не нужен, а проваливание включают словом fallthrough.

switch без выражения

Выражение после switch можно не писать. Тогда в каждом case стоит условие типа bool, и такой switch заменяет цепочку if и else if:

GO
switch t := 25; {
case t < 0:
    fmt.Println("frost")
case t < 30:
    fmt.Println("mild") // mild
case t > 10:
    fmt.Println("warm")
}

Условия в case

Такой switch выполняет первую ветку с истинным условием. В примере условия t < 30 и t > 10 истинны оба, но программа печатает только mild. До case t > 10 дело не доходит.

Здесь указатель в холле перестаёт быть точной картинкой. В указателе каждому отделу соответствует одна строка, а условия в case могут быть верны сразу для нескольких строк. Тогда решает порядок: Go читает ветки сверху вниз и выполняет первую подходящую.

Инициализация

Как и в if, сразу после слова switch можно написать инициализацию — тогда после неё остаётся точка с запятой: switch t := 25; {.

  • Переменная t из инициализации видна во всех ветках.
  • После switch она исчезает, как у if.
  • Без инициализации пишут switch {.

Частая ошибка

В switch без выражения широкое условие поставили выше узкого:

GO
score := 95
switch {
case score >= 60: // ✗
    fmt.Println("pass")
case score >= 90:
    fmt.Println("excellent")
}

Программа печатает pass: условие score >= 60 истинно для 95 и проверяется первым. Ветка score >= 90 не выполнится ни при каком score. Ставьте самое строгое условие первым: сначала score >= 90, затем score >= 60.

Главное

  • switch вычисляет выражение один раз и выполняет case с таким же значением, а default — когда не подошёл ни один.
  • После ветки switch завершается сам: break не нужен, а проваливание включают словом fallthrough.
  • switch без выражения выполняет первую ветку с истинным условием.
  • Поэтому в таком switch самое строгое условие ставят первым.

Подпишись, чтобы пройти курс

Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.

Войти другим способом