Для создания ветвления в программе также существует оператор выбора switch
, в общем виде он выглядит так:
switch (значение) {
case вариант1:
// код
break;
case вариант2:
// код
break;
case вариант3:
// код
break;
default:
// код
break;
}
Оператор перейдёт к коду под меткой с вариантом
, который совпадает со значением
. Если такого варианта нет - выполнится код под меткой default
.
Конструкция switch-case по сути является надстройкой над оператором goto
, где кейсы - это метки
switch
принимает только целочисленные значенияcase
может быть только целочисленной константойcase
не должны повторятьсяdefault
будет выполнен, если не найдётся нужный вариант. Необязательная метка
break #
Оператор break
позволяет покинуть тело switch
, в конце метки или в любом другом месте:
switch (var) {
case 0:
if (условие) break;
// ...
break;
}
Fallthrough #
Если не вызвать break
в конце кода метки - программа перейдёт к выполнению кода следующей по порядку метки, этот переход называется fallthrough (провал) - из одной метки в другую. Провал можно использовать для создания сложных конструкций:
switch (var) {
case 0:
// выполнить, если var == 0
break;
case 1:
// выполнить, если var == 1
break;
case 2:
// выполнить, если var == 2
case 3:
// выполнить, если var == 2 или 3
case 4:
// выполнить, если var == 2, 3 или 4
break;
}
Область видимости #
Код между метками имеет общую область видимости, так как по сути находится внутри одного блока кода. Это означает, что нужно очень аккуратно работать с локальными переменными:
switch (var) {
case 0:
int a;
break;
case 1:
int a; // ошибка компиляции, такая переменная уже есть выше
break;
}
Для решения этой проблемы достаточно обернуть код под меткой в блок:
switch (var) {
case 0: {
int a;
} break;
case 1: {
int a;
} break;
}
Скорость работы #
Логика switch-case
может показаться похожей на if-else
, но работают они абсолютно по разному: если if-else проверяет каждое условие по порядку, пока не дойдёт до нужного, то switch сразу выбирает нужный вариант. Switch работает значительно быстрее if-else, причём его скорость не зависит от количества вариантов, в отличие от if-else.
Диапазон значений в case #
Варианты для case
можно задавать диапазоном значений:
switch (a) {
case 0 ... 100: b = 1; break;
case 101 ... 200: b = 2; break;
case 201 ... 300: b = 3; break;
case 301 ... 400: b = 4; break;
case 401 ... 500: b = 5; break;
case 501 ... 600: b = 6; break;
}
Этот пример равносилен конструкции на if-else
, за исключением скорости работы:
if (a > 0 && a < 100) b = 1;
else if (a < 200) b = 2;
else if (a < 300) b = 3;
else if (a < 400) b = 4;
else if (a < 500) b = 5;
else if (a < 600) b = 6;
Switch + enum #
Довольно частый сценарий использования switch
- разбор и реакция на значение переменной, которая получила своё значение где-то в другом месте программы. Например - обработка текущего режима, который выбран кнопкой:
enum Modes {
Mode1,
Mode2,
Mode3,
};
Modes mode;
// ...
switch (mode) {
case Modes::Mode1:
break;
case Modes::Mode2:
break;
case Modes::Mode3:
break;
}
Здесь есть особенность: если в "кейсах" перечислены не все константы из enum
, то компилятор выдаст предупреждение, что не все варианты обработаны. Если указать default
- предупреждения не будет:
switch (mode) {
case Modes::Mode1:
break;
default:
break;
}