Конструкция switch


Конструкция switch/case похожа на конструкцию if/else, так как позволяет обработать сразу несколько условий:

1
2
3
4
5
6
7
8
9
10
11
12
var num: Int = 22

switch num {
case 0:
print("Переменная равна 0")
case 10:
print("Переменная равна 10")
case 22:
print("Переменная равна 22")
default:
print("не удалось распознать число")
}
После ключевого слова switch идет сравниваемое выражение. Это может быть переменная или константа. Значение этого выражения последовательно сравнивается со значениями, помещенными после оператора сase. И если совпадение будет найдено, то будет выполняться определенный блок сase.

Если совпадение не будет найдено, то выполняется оператор default.

В данном случае так как переменная num равна 22, будет выполняться следующий блок case:

1
2
case 22:
print("Переменная равна 22")
В других языках программирования, в которых также есть конструкция switch/case, обычно в конце блока case ставится оператор break для прерывания выполнения и выхода из блока switch/case. В Swift использовать оператор break в подобных случаях необязательно. Однако бывают случаи, когда мы не хотим обрабатывать какие-то определенные значения и просто хотим выйти из конструкции switch. В этом случае после оператора case или default можно указать оператор break:

1
2
3
4
5
6
7
8
9
10
11
12
var num: Int = 0

switch num {
case 0:
print("Переменная равна 0")
case 10:
break
case 22:
print("Переменная равна 22")
default:
break
}
В данном случае если num равно 10 или другому числу, отличному от 0 или 22, просто произойдет выход из switch.

С помощью знака подчеркивания _ можно задать соответствие всем остальным значениям:

1
2
3
4
5
6
7
8
9
let number = 5
switch number {
case 1:
print("Number = 1")
case 2:
print("Number = 2")
case _:
print("Number не равно ни 1, ни 2, но это не точно")
}
Также мы можем сравнивать выражение не с одним значением, а с группой значений:

1
2
3
4
5
6
7
8
9
10
11
12
var num: Int = 20

switch num {
case 0, 10: // если num равно 0 или 10
print("Переменная равна 0 или 10")
case 11..<20: // если num в диапазоне от 11 до 20, не включая 20
print("Переменная находится в диапазоне от 11 до 20")
case 20...30: // если num в диапазоне от 20 до 30
print("Переменная находится в диапазоне от 20 до 30")
default:
print("не удалось распознать число")
}
Оператор case 0, 10 задает два сравниваемых значения 0 и 10 и срабатывает, если выражение равно одному из этих значений.

Оператор case 11..<20 определяет целый диапазон значений от 11 до 20 (не включая 20) и срабатывает, если выражение равно значению из этого диапазона.

Оператор case 20...30 определяет целый диапазон значений от 20 до 30 (включая оба числа) и срабатывает, если выражение равно значению из этого диапазона.

В версии Swift 4 мы можем опускать одну границу диапазона:

1
2
3
4
5
6
7
8
9
10
let i = 8
switch i {
case ...<0:
print("i - отрицательное число")
case 1...:
print("i - положительное число")
case 0:
print("i равно 0")
default:break
}
Кортежи в switch/case
Кроме выражений простых типов можно сравнивать кортежи:

1
2
3
4
5
6
7
8
9
10
11
12
13
let personInfo = ("Tom", 22)
switch personInfo {
case ("Bob", 33):
print("Имя: Bob, возраст: 33")
case (_, 22):
print("Имя: \(personInfo.0) и возраст: 22")
case ("Tom", _):
print("Имя: Tom и возраст: \(personInfo.1))
case ("Tom", 1...30):
print("Имя: Tom и возраст от 1 до 30)
default:
print("Информация не распознана")
}
Здесь кортеж personInfo последовательно сравнивается с тремя кортежами в операторах case. При сравнении мы можем задать полный кортеж:

1
2
case ("Bob", 33):
print("Имя: Bob, возраст: 33")
Либо мы также можем опустить один из элементов кортежа, подставив вместо него знак подчеркивания _:

1
2
case (_, 22):
print("Имя: \(personInfo.0) и возраст: 22")
В этом случае не имеет значение, чему равен первый элемент кортежа, главное, чтобы второй элемент кортежа был равен 22.

Для числовых данных мы также можем задать не точное значение, а диапазон значений:

1
2
case ("Tom", 1...30):
print("Имя: Tom и возраст от 1 до 30)
В этом случае второй элемент кортежа должен находиться в диапазоне от 1 до 30.

В использованной нами выше конструкции switch/case сравниваемому выражению соответствуют аж три оператора case - второй, третий и четвертый, но выполняться будет только первый из них.

Но если мы хотим, чтобы также выполнялся и следующий оператор case (или оператор default), то в конце предыдущего блока case следует использовать оператор fallthrough:

1
2
3
4
5
6
7
8
9
10
11
12
let personInfo = ("Tom", 22)
switch personInfo {
case ("Bob", 33):
print("Имя: Bob, возраст: 33")
case (_, 22):
print("Имя: \(personInfo.0) и возраст: 22")
fallthrough
case ("Tom", _):
print("Имя: Tom и возраст: \(personInfo.1))
default:
print("Информация не распознана")
}
Связывание значений
Механизм связывания значений позволяет определить в блоках case переменные и константы, значения которых будут связаны со значением сравниваемого выражения:

1
2
3
4
5
6
7
8
9
let number = 5
switch number {
case 1:
print("Number = 1")
case 2:
print("Number = 2")
case let n:
print("Number = \(n)")
}
В данном случае если значение number не равно 1 и 2, то оно передается константе n, которая используется в рамках своего блока case.

При этом привязка может выполняться к переменным и константам более сложных типов, например, кортежей:

1
2
3
4
5
6
7
8
9
let personInfo = ("Tom", 22)
switch personInfo {
case (let name, 22):
print("Имя: \(name) и возраст: 22")
case ("Tom", let age):
print("Имя: Tom и возраст: \(age)")
case let (name, age):
print("Имя: \(name) и возраст: \(age)")
}
Если второй элемент в personInfo равен 22, то срабатывает блок

1
2
case (let name, 22):
print("Имя: \(name) и возраст: 22")
Здесь переменная name получает значение первого элемента из кортежа personInfo.

Причем в этой конструкции не используется блок default, так как блок

1
2
case let (name, age):
print("Имя: \(name) и возраст: \(age)")
фактически перекрывает все возможные случаи, которые не попадают под предыдущие операторы case. В этом блоке определяется константа (хотя это может быть и переменная), которая состоит из элементов кортежа personInfo.

Оператор where
Если при выполнении блока case мы хотим задать дополнительные условия, то в этом случае нам поможет оператор where. Например:

1
2
3
4
5
6
7
8
9
10
let i = 8
switch i {
case let k where k < 0:
print("i - отрицательное число")
case let k where k > 0:
print("i - положительное число")
case 0:
print("i is 0")
default:break
}
Пример с кортежами:

1
2
3
4
5
6
7
8
9
10
11
12
let personInfo = ("Tom", 22)
switch personInfo {

case ("Tom", _) where personInfo.1 > 10 && personInfo.1 < 15:
print("Имя: Tom и возраст от 10 до 15")

case ("Tom", _) where personInfo.1 >= 20:
print("Имя: Tom и возраст от 20 и выше")

default:
print("Неизвестно")
}
Выражения where определяют дополнительные условия. И если они не выполняются, то соответственно блок case тоже не выполняется.