Управление потоком (Flow Control)
Код в программе выполняется последовательно, сверху вниз, от строчки к строчке. Создается поток кода. И компилятор считывает код так же - от строки к строке.
Это похоже на речной поток. Река не может просто так прерваться и возникнуть в другом месте. Чтоб это стало возможно - необходимо создать, например, какой-то тунель или переход.
В программировании похожая ситуация. Раньше программы были более простыми и использовался для таких переходов оператор “goto”, который позволял перейти к необходимой строке кода. Таким образом поток программы не прерывался, а переходил из одной строки в другую.
В современном программировании программы стали сложнее, объёмнее, составляют многие сотни строчек кода. Логика современных программ более сложна и алгоритмы решения задач требуют либо разделения потока в зависимости от условий, либо повторения части кода при определённых условиях. В первом случае, создаются ветвления (Branch), во втором - циклы (петли, Loop).
Немного про алгоритмы
Схема алгоритма — графическое представление алгоритма, дополняемое элементами словесной записи. Каждый пункт алгоритма отображается на схеме некоторой геометрической фигурой или блоком. При этом правило выполнения схем алгоритмов регламентирует ГОСТ 19.002—80 «Единая система программной документации».
Блоки на схемах соединяются линиями потоков информации. Основное направление потока информации идет сверху вниз и слева направо (стрелки могут не указываться), снизу вверх и справа налево — стрелка обязательна. Количество входящих линий для блока не ограничено. Выходящая линия — одна, за исключением логического блока.
К основным структурам относятся следующие — линейные, разветвляющиеся, циклические.
На этом изображении - Базовые структуры алгоритмов и программ:
- а - линейный алгоритм;
- б - алгоритм с ветвлением;
- в - алгоритм с циклом While (Пока);
- г — алгоритм с циклом For (До);
- д — пример алгоритма вычисления факториала.
Линейными называются алгоритмы, в которых действия осуществляются последовательно друг за другом. Стандартная блок-схема линейного алгоритма приводится на рисунке (изображение а).
Разветвляющимся называется алгоритм, который, в отличие от линейных алгоритмов, содержит условие, в зависимости от истинности или ложности которого выполняется та или иная последовательность команд. Таким образом, команда ветвления состоит из условия и двух последовательностей команд (изображение б).
В качестве условия в разветвляющемся алгоритме может быть использовано любое понятное исполнителю утверждение, которое может соблюдаться (быть истинно) или не соблюдаться (быть ложно). Такое утверждение может быть выражено как словами, так и формулой. Таким образом, команда ветвления состоит из условия и двух последовательностей команд.
Циклическим называется алгоритм, в котором некоторая последовательность операций (тело цикла) выполняется многократно. Однако «многократно» не означает «до бесконечности». Организация циклов, никогда не приводящая к остановке в выполнении алгоритма, является нарушением требования его результативности — получения результата за конечное число шагов (изображение в).
В цикл в качестве базовых входят следующие структуры: блок проверки условия и тело цикла. Перед операцией цикла осуществляется начальное присвоение значений тем переменным, которые используются в теле цикла.
Если тело цикла расположено после проверки условий (цикл с предусловием), то может случиться, что при определенных условиях блок «тело цикла» не выполнится ни разу. Такой вариант организации цикла, управляемый предусловием, называется цикл “Пока” (While) — здесь условие — это условие продолжения цикла.
Возможен другой случай, когда тело цикла выполняется, по крайней мере, один раз и будет повторяться до тех пор, пока не станет истинным условие. Такая организация цикла, когда его тело расположено перед проверкой условия, носит название цикла с постусловием, или цикла “До” (For).
Современные языки программирования имеют достаточный набор операторов, реализующих как цикл “Пока”, так и цикл “До”.
Пример алгоритма вычисления факториала, изображенный на рисунке выше (фиг. д) (с циклом “Пока”). Переменная N получает значение числа, факториал которого вычисляется. Переменной N, которая в результате выполнения алгоритма должна получить значение факториала, присваивается первоначальное значение “1”. Переменной К также присваивается значение “1”. Цикл будет выполняться, пока справедливо условие “N > К”. Тело цикла состоит из двух операций “N = N x K” и “К = К + 1”.
Циклические алгоритмы, в которых тело цикла выполняется заданное число раз, реализуются с помощью цикла со счетчиком. Цикл со счетчиком реализуется с помощью команды повторения.
Алгоритм ветвления указан на рисунке в общем виде. Возможно несколько видов данного алгоритма.
- Алгоритм ветвления 1 - “Если …, то …”.
Работа алгоритма. Если условие выполнится, то будет выполнено определенное действие. Если условие не выполниться, то ничего не произойдет и выполнение алгоритма пойдёт дальше.
- Алгоритм ветвления 2 - “Если …, то …; иначе …”.
Работа алгоритма. Если условие выполнится, то будет выполнено определенное действие. Иначе, если условие не выполниться, то будет выполнено другое действие. После ветвления выполнение алгоритма пойдёт дальше.
- Алгоритм ветвления 3 - “Если …, то …; еще если …, то …; …; иначе …”.
Работа алгоритма. Если условие выполнится, то будет выполнено определенное действие. Иначе, если условие не выполнится, то будет проверено следующее условие и если оно будет выполнено - будет выполнено определенное действие. Дальше, таким же образом проверяются остальные условия. Иначе, если ни одно условие не выполниться, то будет выполнено еще одно действие. После ветвления выполнение алгоритма пойдёт дальше.
Процесс решения сложной задачи довольно часто сводится к решению нескольких более простых подзадач. Соответственно при разработке сложного алгоритма он может разбиваться на отдельные алгоритмы, которые называются вспомогательными. Каждый такой вспомогательный алгоритм описывает решение какой-либо подзадачи.
Процесс построения алгоритма методом последовательной детализации состоит в следующем. Сначала алгоритм формулируется в «крупных» блоках (командах), которые могут быть непонятны исполнителю (не входят в его систему команд), и записываются как вызовы вспомогательных алгоритмов. Затем происходит детализация, и все вспомогательные алгоритмы подробно расписываются с использованием команд, понятных исполнителю.
Условные выражения
Условные выражения используются для принятие решений в вашем коде:
если условие верно, сделай это
К примеру:
- Если пользователь успешно залогинен, мы загружаем его твиты;
- Если твит содержит фотографию, мы используем особый интерфейс для ее отображения;
- Если твит содержит определенные слова, мы генерируем хэштеги;
- Принятие подобных решений называется управлением потока кода, потому что мы разделяем поток кода на отдельные ветви.
Для управления потоком в Swift используются два вида действий - ветвления и циклы. В обоих этих действиях есть обязательная часть - условные выражения.
Ветвления в явном виде используют условные выражения. Ветвления создают два или более потока в зависимости от условий (условных выражений). Поэтому операторы, которые используются в ветвлениях называются условными операторами.
Циклы используют условные выражения (в явном и неявном виде) для проверки условия выполнения самого цикла. Циклы (петли) заставляют выполнять часть кода повторно в зависимости от условий (условных выражений). И имеют также блок с кодом, который повторяется необходимое количество раз (тело цикла). Поэтому такие операторы чаще называют операторами цикла.
Булева логика
Условные выражения используют булеву логику для возврата либо true
, либо false
. В Swift данный тип обозначается как Bool
.
Пример:
let isLoggedIn: Bool = false
if isLoggedIn {
print("Секретное сообщение")
}
В этом примере, условное выражение isLoggedIn
указано после оператора if
. Его значение оценивается как ложное (false), так как значение константы isLoggedIn
напрямую указано как false
. Если значение поменять на правдивое (true), тогда условие выполниться и код внутри блока if
будет выполнен.
Также можно получить значение условного выражения с помощью операторов сравнения или логических операторов.
Условные выражения и операторы сравнения
Swift имеет следующие операторы сравнения:
- Равно: a == b;
- Не равно: a != b;
- Больше, чем: a > b;
- Меньше, чем: a < b;
- Больше или равно: a >= b;
- Меньше или равно: a <= b.
Результатом выполнения даных операторов будет логическое значение (true, false) по типу Bool
.
Операторы сравнения используются для сравнений значений друг с другом. Когда сравниваете два значения, оба из них должны иметь одинаковый тип. Нет смысла проверять, равна ли строка целому числу. Поэтому приведенный ниже код приведет к ошибке компилятора:
let room: Int = 123
let input: String = "123"
if room == input {
print("Комната недоступна")
}
Можно даже сравнивать строки друг с другом. Таким образом, мы можем проверить, меньше ли «abcd», чем «efgh»:
"abcd" < "efgh"
// true
Выражение:
if isLoggedIn {
print("Секретное сообщение")
}
проверяет, равно ли значение isLoggedIn
true
. Этот код также можно написать следующим образом:
if isLoggedIn == true {
//
}
Условные выражения и логические операторы
Также доступны логические операторы.
Есть 3 логических оператора:
И
обозначается как&&
;ИЛИ
обозначается как||
;НЕ
обозначается как!
.
Операторы &&
и ||
помещаются между двумя значениями, например a && b
или a || b
. Оператор !
является префиксом, поэтому его необходимо поставить перед одним значением, например !a
.
- Выражение с оператором
И
возвращаетtrue
, когда оба его операнда имеют значениеtrue
. Когда любой из операндов имеет значениеfalse
, возвращаетсяfalse
; - Выражение с оператором
ИЛИ
возвращаетtrue
, когда один из операндов имеет значениеtrue
. Когда оба операнда являютсяfalse
, возвращаетсяfalse
; - Выражение с оператором
НЕ
возвращает значение, противоположное текущему значению, поэтомуtrue
превращаетсяfalse
, аfalse
становитсяtrue
.
Больше про операторы можно узнать в отдельной статье. См. ссылку внизу.
Ветвления (Branches)
Для организации схем алгоритма с ветвлением в языке Swift используются условные операторы (Conditional Statements). Есть три условных оператора:
- Оператор If (If Statement);
- Оператор Switch (Switch Statement);
- Оператор Guard (Guard Statement).
Условный оператор If (If Statement)
В Swift используется оператор if
для запуска блочного кода только при выполнении определенного условия.
Например, выставление оценок (А, В, С) на основании оценок, полученных учащимся.
- если процент выше 90, присвоить оценку A;
- если процент выше 75, присвоить оценку B;
- если процент выше 65, присвоить оценку C.
В Swift есть три формы оператора if
.
- if statement - отвечает за алгоритм ветвления 1;
- if…else statement - отвечает за алгоритм ветвления 2;
- if…else if…else statement - отвечает за алгоритм ветвления 3.
1. Swift If Statement
Синтаксис оператора if
Синтаксис оператора if
в Swift:
if (condition) {
// body of if statement
}
Оператор if
оценивает условие внутри круглых скобок (condition)
.
- Если условие (condition) оценивается как истинное (true), выполняется код внутри тела
if
; - Если условие (condition) оценивается как ложное (false), код внутри тела
if
пропускается.
Примечание. Код внутри
{ }
является телом оператораif
.
Схема работы оператора if и пример использования
Пример использования:
let number = 10
// check if number is greater than 0
if (number > 0) {
print("Number is positive.")
}
print("The if statement is easy")
// Output
// Number is positive.
// The if statement is easy
В приведенном выше примере создали переменную с именем number
. Обратите внимание на условие теста:
number > 0
Здесь, поскольку number
больше 0, условие оценивается как истинное (true). Следовательно, код внутри тела if
выполняется.
Если изменить переменную на отрицательное целое число. Скажем -5
:
let number = -5
Теперь, когда мы запустим программу, вывод будет таким:
// The if statement is easy
Это связано с тем, что значение number
меньше 0. Следовательно, условие оценивается как ложное (false). И тело блока if
пропускается.
2. Swift If…else Statement
Синтаксис оператора if…else
Синтаксис оператора if...else
в Swift:
if (condition) {
// block of code if condition is true
} else {
// block of code if condition is false
}
Оператор if...else
оценивает условие внутри круглых скобок ()
.
- Если условие (condition) оценивается как истинное (true):
- код внутри
if
выполняется; - код внутри
else
пропускается;
- код внутри
- Если условие (condition) оценивается как ложное (false):
- код внутри
if
пропускается; - код внутри
else
выполняется.
- код внутри
Схема работы оператора if…else и пример использования
Пример использования:
let number = 10
if (number > 0) {
print("Number is positive.")
} else {
print("Number is negative.")
}
print("This statement is always executed.")
// Output
// Number is positive.
// This statement is always executed.
В приведенном выше примере создали переменную с именем number
. Обратите внимание на условие теста:
number > 0
Здесь, поскольку number
больше 0, условие оценивается как истинное (true). Следовательно, код внутри тела if
выполняется.
Если изменить переменную на отрицательное целое число. Скажем -5
:
let number = -5
Теперь, когда мы запустим программу, вывод будет таким:
// Number is negative.
// This statement is always executed.
Здесь тестовое выражение оценивается как ложное (false). Следовательно, выполняется код внутри тела else
.
3. Swift if…else if…else Statement
Синтаксис оператора if…else if…else
Оператор if...else
используется для выполнения блока кода среди двух альтернатив. Однако, если нужно сделать выбор между более чем двумя альтернативами, используется оператор if...else if...else
.
Синтаксис оператора if...else if...else
в Swift:
if (condition1) {
// code block 1
} else if (condition2) {
// code block 2
} else {
// code block 3
}
В этом примере:
- Если
условие1
(condition1
) оценивается как истинное (true
), выполняется блок кода 1 (code block 1
); - Если
условие1
(condition1
) оценивается как ложное (false
), то оцениваетсяусловие2
(condition2
):- Если
условие2
(condition2
) истинно (true
), выполняется блок кода 2 (code block 2
); - Если
условие2
(condition2
) ложно (false
), выполняется блок кода 3 (code block 3
).
- Если
Если необходимо больше вариантов в решении - можно добавлять необходимое количество блоков else if
.
Схема работы оператора if…else if…else и пример использования
Пример использования:
// check whether a number is positive, negative, or 0.
let number = 0
if (number > 0) {
print("Number is positive.")
} else if (number < 0) {
print("Number is negative")
} else {
print("Number is 0.")
}
print("This statement is always executed")
// Output
// Number is 0.
В приведенном выше примере создали переменную с именем number
со значением 0
. Здесь есть два выражения условия:
if (number > 0)
— проверяет, больше ли число 0;else if (number < 0)
— проверяет, меньше ли число 0.
Здесь оба условия оцениваются как ложные (false). Следовательно, выполняется код внутри тела else
.
Вложенный оператор if
Можно использовать оператор if
внутри оператора if
. Это называется вложенным оператором if.
Синтаксис вложенного оператора if:
// outer if statement
if (condition1) {
// statements
// inner if statement
if (condition2) {
// statements
}
}
Заметки:
- При необходимости можно добавить операторы
else
иelse if
во внутренний операторif
; - Мы также можем вставить внутренний оператор
if
во внешний операторelse
илиelse if
(если они существуют); - Можно вложить несколько слоев операторов
if
.
Синтаксис вложенного оператора if…else:
var number = 5
// outer if statement
if (number >= 0) {
// inner if statement
if (number == 0) {
print("Number is 0")
} else { // inner else statement
print("Number is positive")
}
} else { // outer else statement
print("Number is negative")
}
// Output
// Number is positive
В приведенном выше примере использовался вложенный оператор if, чтобы проверить, является ли заданное число положительным, отрицательным или равным 0.
Тернарный оператор и оператор if
Тернарный оператор аналогичен простой конструкции if
и имеет следующий синтаксис:
(condition) ? (code if true) : (code if false)
В зависимости от условия тернарный оператор возвращает второй или третий операнд:
- если условие равно
true
, то возвращается второй операнд; - если условие равно
false
, то третий.
Например, такой код с оператором if-else
:
var num1 = 10
var num2 = 6
var num3 = 0
if num1 > num2 {
num3 = num1 - num2
} else {
num3 = num1 + num2
}
print(num3)
// Output
// 4
Можно заменить на конструкцию с тернарным оператором:
var num1 = 10
var num2 = 6
var num3 = num1 > num2 ? num1 - num2 : num1 + num2
print(num3)
// Output
// 4
В данном случае num3
будет равно 4
, так как num1
больше num2
, поэтому будет выполняться второй операнд: num1 - num2
.
Тернарный оператор часто называют тернарный условный оператор, так как он используется только для такой проверки условий.
Его удобно использовать для простой конструкции if-else
. Использовать его для большего количества ветвлений возможно (подставляя во второй и третий операнд другие тернарные операторы), но тогда код становится сильно сложнее для чтения и понимания.
Сравните код с оператором if-else
:
var num1 = 10
var num2 = 6
var num3 = 0
if num1 > num2 {
if num1 > 0 {
num3 = num1 - num2
} else {
num3 = 0
}
} else {
if num2 > 0 {
num3 = num1 + num2
} else {
num3 = 0
}
}
print(num3)
// Output
// 4
С кодом, который использует тернарный оператор:
var num1 = 10
var num2 = 6
var num3 = num1 > num2 ? num1 > 0 ? num1 - num2: 0 : num2 > 0 ? num1 + num2 : 0
print(num3)
// Output
// 4
Код с использованием тернарного оператора в этом случае - сложнее для восприятия.
Больше про операторы можно узнать в отдельной статье. См. ссылку внизу.
Условный оператор Switch (Switch Statement)
Оператор switch
позволяет выполнить блок кода среди множества альтернатив.
Оператор switch
позволяет проверить определенное значение и сравнить его с несколькими условиями. Это особенно эффективно для принятия решений на основе переменной, которая может содержать ряд возможных значений. Использование оператора switch
позволяет использовать более краткий и удобный синтаксис кода.
Синтаксис оператора switch
Синтаксис оператора switch
в Swift следующий:
switch (expression) {
case value1:
// statements
case value2:
// statements
...
...
default:
// statements
}
Оператор switch
оценивает выражение в круглых скобках (expression)
:
- Если результат выражения равен
значению1
(value1
), выполняются выражения, которые указаны в оператореcase value1:
; - Если результат выражения равен
значению2
(value2
), выполняются выражения, которые указаны в оператореcase value2:
; - Если совпадения нет, выполняются выражения, которые указаны в операторе по умолчанию (
default:
).
Примечание: Можно сделать то же самое с конструкцией
if...else...if
. Однако синтаксис оператораswitch
чище, и его намного легче читать и писать.
Важно. Оператор
switch
должен иметь выражения на все случаи - Операторswitch
должен быть исчерпывающим. Именно для этого указывается значения по умолчанию. Возможно не использоватьdefault
, если учтены все варианты. Например в перечислениях (Enum).
Схема работы оператора switch и пример использования
Пример использования:
// program to find the day of the week
let dayOfWeek = 4
switch dayOfWeek {
case 1:
print("Sunday")
case 2:
print("Monday")
case 3:
print("Tuesday")
case 4:
print("Wednesday")
case 5:
print("Thursday")
case 6:
print("Friday")
case 7:
print("Saturday")
default:
print("Invalid day")
}
// Output
// Wednesday
В приведенном выше примере переменной dayOfWeek
было присвоено значение 4
. Теперь переменная сравнивается со значением каждого оператора case
. Поскольку значение соответствует case 4
, выполняется часть кода print("Wednesday")
внутри case
, и программа завершается.
В том случае, если переменной dayOfWeek
будет присвоенно значение, которое не сооответствует ни одному case
(например: -2, 0, 9, “23”) - будет выполнен код по умолчанию (print("Invalid day")
).
Если на несколько вариантов условий необходимо выполнить один и тот же код - то несколько условий можно объединить в одном case
и записать их через запятую - получится составной кейс.
Пример:
// program to find the day of the week
let dayOfWeek = 4
switch dayOfWeek {
case 1, 2, 3, 4, 5:
print("I am working today")
case 6, 7:
print("I am resting today")
default:
print("Invalid day")
}
// Output
// I am working today
Использование Switch Statement с оператором передачи управления break
Если использовать ключевое слово break
внутри оператора case
или default
, тогда элемент управления прекращает действие инструкции switch
и код продолжает свою работу за блоком switch
.
Например, можно указать оператор break
в блоке default
, если действие по умолчанию не предусмотрено.
Использование Switch Statement с оператором передачи управления fallthrough
Если использовать ключевое слово fallthrough
внутри оператора case
, тогда элемент управления переведет выполнение кода к следующему case
, даже если значение case
не совпадает с выражением switch
.
Например:
let dayOfWeek = 4
switch dayOfWeek {
case 1:
print("Sunday")
case 2:
print("Monday")
case 3:
print("Tuesday")
case 4:
print("Wednesday")
fallthrough
case 5:
print("Thursday")
case 6:
print("Friday")
case 7:
print("Saturday")
default:
print("Invalid day")
}
// Output
// Wednesday
// Thursday
Switch Statement с диапазонами (Range)
Пример:
let ageGroup = 33
switch ageGroup {
case 0...16:
print("Child")
case 17...30:
print("Young Adults")
case 31...45:
print("Middle-aged Adults")
default:
print("Old-aged Adults")
}
// Output
// Middle-aged Adults
В приведенном выше примере вместо одного значения были использованы числовые диапазоны для каждого случая: case 0...16
, case 17...30
и case 31...45
. Здесь значение ageGroup
равно 33
, которое попадает в диапазон от 32 до 45. Следовательно, выполняется функция print("Middle-aged Adults")
.
Кортежи (Tuple) в Switch Statement
В Swift можно использовать кортежи в операторах switch
. Можно использовать кортежи для тестирования нескольких значений в одной и той же инструкции switch
. Каждый элемент кортежа может быть протестирован с любой величиной или с диапазоном величин. Так же можно использовать идентификатор подчеркивания (_
) для соответствия любой возможной величине.
Например:
let info = ("Dwight", 38)
// match complete tuple values
switch info {
case ("Dwight", 38):
print("Dwight is 38 years old")
case ("Micheal", 46):
print("Micheal is 46 years old")
default:
print("Not known")
}
// Output
// Dwight is 38 years old
В приведенном выше примере был создан кортеж с именем info
со значениями: "Dwight"
и 38
. Здесь вместо одного значения каждый оператор case
также включает в себя кортежи: case ("Dwight", 38)
и case ("Micheal", 46)
. Теперь значение info
сравнивается с каждым оператором case
. Поскольку значение совпадает с case ("Dwight", 38)
, выполняется функция print("Dwight is 38 years old")
.
Еще пример:
for i in 1...100 {
switch (i % 3 == 0, i % 5 == 0) {
case (true, false):
print("Fizz")
case (false, true):
print("Buzz")
case (true, true):
print("FizzBuzz")
default:
print(i)
}
}
В приведенном выше коде создается кортеж для проверки из двух значений: результат вычисления i % 3 == 0
и результат вычисления i % 5 == 0
. Теперь можно учитывать различные значения кортежей: (true, false)
, (false, true)
, (true, true)
. Если ни один из этих случаев не совпадает, тогда выводится значение i
.
Поскольку используем switch
для проверки значений кортежа, то также можно проверять различные совпадающие значения в кортеже:
let airplane = (type: "737-800", heading: "LAX")
switch airplane {
case ("737-800", _):
print("Этот самолет модели 737-800.")
case (let type, "LAX"):
print("Этот \(type) летит в аэропорт Лос-Анджелеса.")
default:
print("Неизвестный самолет.")
}
// Output
// Этот самолет модели 737-800.
В приведенном выше коде рассмотрено 3 разных случая для константы airplane
, которая представляет собой кортеж по типу (String, String):
("737-800", _)
- первое значение совпадает, второе значение не рассматривается, может быть любым;(let type, "LAX")
- первое значение связывается с константойtype
, но не проверяется в условии, второе значение совпадает;default
- остальные случаи.
Выражение let type
называется связыванием значения. Это позволяет привязать значение кортежа к константе. Теперь внутри блока case
можно использовать эту константу, например, распечатать ее.
Если необходимо привязать все значения в кортеже, то ключевое слово let
можно вынести за пределы кортежа.
Пример:
let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
print("(\(x), \(y)) is just some arbitrary point")
}
// Output
// (1, -1) is on the line x == -y
Составные кейсы так же могут включать в себя привязку значения. Все шаблоны составных кейсов должны включать в себя тот же самый набор значений и каждая связка должна быть одного и того же типа из всех шаблонов составного кейса. Это гарантирует тот факт, что независимо от того, какая часть составного кейса совпала со сравниваемым значением, код в теле всегда получит доступ к значению привязки и это значение всегда будет одного типа.
Пример:
let stillAnotherPoint = (9, 0)
switch stillAnotherPoint {
case (let distance, 0), (0, let distance):
print("On an axis, \(distance) from the origin")
default:
print("Not on an axis")
}
// Output
// On an axis, 9 from the origin
Кейс выше имеет два шаблона: (let distance, 0)
, который соответсвует любой точке на оси “x”, и (0, let distance)
, что соответствует точке на оси “y”. И тот и другой шаблон включают в себя привязку для distance и distance является целочисленным значением для двух этих шаблонов, что значит, что код внутри тела кейса всегда будет иметь доступ к значению distance
.
Больше о кортежах (tuples) можно узнать в отдельной статье. См. ссылку внизу.
Использование switch с оговоркой where
Также можно использовать switch
с оператором where
:
enum Response {
case error(Int, String)
case success
}
let httpResponse = Response.success
switch httpResponse {
case .error(let code, let status) where code > 399:
print("HTTP Ошибка: \(code) \(status)")
case .error:
print("HTTP запрос неуспешен")
case .success:
print("HTTP запрос успешен")
}
// Output
// HTTP запрос успешен
В приведенном коде происходят две вещи:
- Создаем перечисление
Response
, которое имеет два случая:.error
и.success
. Случай.error
имеет два соответствующие значения: целое число и строку; - Программа оценивает значение
httpResponse
с помощью оператораswitch
, реагируя на разные значения перечисленияResponse
.
Если изменить значение httpResponse
:
let httpResponse = Response.error(404, "Not Found")
// Output
// HTTP Ошибка: 404 Not Found
Или:
let httpResponse = Response.error(301, "Moved Permanently")
// Output
// HTTP запрос неуспешен
Есть еще один .error
случай, который нас особенно интересует, а именно код ошибки, который больше, чем 399
.
Коды состояния HTTP, которые используются в интернете, указывают на то, что коды состояния от 400 и выше являются ошибками клиента и сервера. Иными словами, когда получаете один из них - то тогда что-то пошло не так.
В приведенном выше коде используется привязка значений для констант code
и status
соответствующих значений перечисления Response
. Также используется ключевое слово where
, чтобы указать, что этот случай должен выполняться для любого значения code
, который превышает значение 399
.
Использование switch с перечислениями
Перечисления имеют схожий синтаксис с оператором switch
.
Рассмотрим следующее перечисление:
enum Compass {
case north
case east
case south
case west
}
Если необходимо найти нужное направление, можно использовать следующий код:
let heading = Compass.south
if heading == .north {
print("Вы направляетесь на север!")
} else if heading == .east {
print("Вы направляетесь на восток!")
} else if heading == .south {
print("Вы направляетесь на юг!")
} else if heading == .west {
print("Вы направляетесь на запад!")
}
Приведенный выше код использует оператор if
для оценки значения heading
и вывода соответствующей строки текста.
Можно сделать то же самое, используя оператор switch
:
switch heading {
case .north:
print("Вы направляетесь на север!")
case .east:
print("Вы направляетесь на восток!")
case .south:
print("Вы направляетесь на юг!")
case .west:
print("Вы направляетесь на запад!")
}
Сначала используется ключевое слово switch
, а затем проверяемое выражение, в данном случае это константа heading
. Это значение, которое рассматривается блоками switch
. Затем перебираются возможные варианты значений с помощью case
. В приведенном выше примере - рассматриваются все возможные значения перечисления Compass
.
Так как все варианты в перечислении указаны, в блоке switch
можно не указывать блок default
.
Особенностью switch
является то, что каждый switch
блок должен быть исчерпывающим. Если не включить вариант с .east
произойдет следующее:
switch heading {
case .north:
print("Вы направляетесь на север!")
case .south:
print("Вы направляетесь на юг!")
case .west:
print("Вы направляетесь на запад!")
}
// Output
// error: switch must be exhaustive
В этом примере появляется ошибка, которая сообщает, что оператор switch
должен быть исчерпывающим.
Особенности работы с оператором switch
Даже если заявление со switch
должно быть исчерпывающим, не нужно явно указывать каждый параметр.
Рассмотрим перечисление Authorization
:
enum Authorization {
case granted
case undetermined
case unauthorized
case denied
case restricted
}
Если необходимо предоставить пользователю доступ к ресурсу в зависимости от его состояния авторизации, можно сделать это:
switch state {
case .granted:
print("Доступ разрешен.")
default:
print("Доступ закрыт!")
}
В приведенном выше коде параметр default
используется для ответа на любой необработанный случай. Это делает выражение со switch
исчерпывающим.
Также можно проверить более сложные случаи:
switch state {
case .granted:
print("Доступ разрешен.")
case .undetermined:
print("Предоставьте код доступа.")
case .unauthorized, .denied, .restricted:
print("Доступ закрыт!")
}
Последний случай объединяет несколько случаев в одной строке.
Для того, чтобы было выполнено несколько условий, можно использовать оператор передачи управления fallthrough
:
var message = "Ответ: "
let state = Authorization.undetermined
switch state {
case .granted:
message += "Доступ открыт. Вы можете продолжить"
case .undetermined:
message += "Предоставьте код доступа."
fallthrough
default:
message += "Доступ закрыт!"
}
print(message)
// Output
// Ответ: Предоставьте код доступа. Доступ закрыт!
В приведенном выше примере выполняется как условие .undetermined
, так и default
.
Условный оператор Guard (Guard Statement)
В Swift используется оператор guard
для передачи управления программой за пределы области видимости, когда определенные условия не выполняются.
Оператор guard
похож на оператор if
с одним существенным отличием. Оператор if
запускается, когда выполняется определенное условие. Однако оператор guard
запускается, когда определенное условие не выполняется.
Синтаксис оператора guard
Синтаксис оператора guard
:
guard expression else {
// statements
// control statement: return, break, continue or throw.
}
Здесь выражение (expression) возвращает либо истину (true), либо ложь (false). Если выражение оценивается как
- true - операторы внутри блока кода
guard
не выполняются; - false - операторы внутри блока кода
guard
выполняются.
Примечание. Необходимо использовать операторы передачи управления:
return
,break
,continue
илиthrow
для выхода из области видимостиguard
.
Важно. Так как оператор
guard
использует выход из области видимости, то нельзя использовать операторguard
в глобальной области видимости.
Схема работы оператора guard и пример использования
Пример использования:
var i = 2
while (i <= 10) {
// guard condition to check the even number
guard i % 2 == 0 else {
i = i + 1
continue
}
print(i)
i = i + 1
}
// Output
// 2
// 4
// 6
// 8
// 10
В приведенном выше примере использовался оператор guard
, чтобы проверить, является ли число четным или нечетным. Обратите внимание на строку:
guard i % 2 == 0 else {...}
Здесь, если i
- нечетное, то выражение
i % 2 == 0
оценивается как ложное (false). И код внутриguard
выполняется; - чётное, то выражение
i % 2 == 0
оценивается как правдивое (true). И код внутриguard
пропускается.
Следовательно, на выходе получаем только четные числа. Здесь использовался оператор continue
внутри guard
, чтобы передать управление следующей итерации цикла.
Использование управляющих операторов, таких как
continue
,break
и т.д., является обязательным. В противном случае - получим ошибку:‘guard’ body must not fall through, consider using a ‘continue’ or ‘return’ to exit the scope
Оператор guard внутри функции
Оператор Guard обычно используется с функциями. Функция — это блок кода, выполняющий определенную задачу. Чтобы узнать больше, посетите Swift Function. Давайте посмотрим, как мы можем использовать оператор защиты с функциями.
Пример:
// create a function
func checkOddEven(number: Int) {
// use of guard statement
guard number % 2 == 0 else {
print("Odd Number")
return
}
print("Even Number")
}
// function call
checkOddEven(number: 3)
// Output
// Odd Number
В приведенном выше примере создали функцию с именем checkOddEven(number: Int)
. Обратите внимание на использование оператора guard
внутри функции.
Здесь оператор защиты проверяет, является ли число четным или нечетным. Поскольку число нечетное, условие number % 2 == 0
возвращает false
(оценивается как ложное). Следовательно, код внутри оператора guard
выполняется.
Теперь изменим значение число в вызове функции на четное число, например, 4:
// function call
checkOddEven(number: 4)
// Output
// Even Number
Здесь, поскольку число четное, условия number % 2 == 0
возвращает true
(оценивается как истинное). Таким образом, код внутри оператора guard
пропускается, а другой код внутри функции выполняется. Следовательно, получаем четное число в качестве вывода.
Guard с несколькими условиями
Операторы guard
также может объединять несколько условий, разделенных запятой (,
):
func checkJobEligibility(age: Int) {
guard age >= 18, age <= 40 else {
print("Not Eligible for Job")
return
}
print("You are eligible for this job")
}
// function call
checkJobEligibility(age: 33)
// Output
// You are eligible for this job
В приведенном выше примере оператор guard
содержит два условия, разделенных запятой. Здесь будет “Логическое И” между двумя условиями. То есть guard
условие истинно, только если оба условия true
.
Guard-let Statement
При работе с опционалами Swift оператор guard
используется как оператор guard-let
.
Например:
func checkAge(age: Int?) {
guard let myAge = age else {
print("Age is undefined")
return
}
print("My age is \(myAge)")
}
// function call
checkAge(age: 22)
// Output
// My age is 22
В приведенном выше примере используется оператор guard-let
, чтобы проверить, содержит ли входящий параметр функции age
значение или нет. Поскольку age
содержит некоторое значение, код внутри блока guard-let
не выполняется. Это работает так же, как если бы условие guard
было истинным.
Guard Statement или If Statement
Оператор guard
вводится как альтернатива оператору if
. Например, предположим, необходимо проверить, имеет ли человек право голосовать. Можно использовать оператор if
:
func voteEligibility(age: Int) {
if age >= 18 {
print("Eligible to vote")
} else {
print("Not eligible to vote")
}
}
// function call
voteEligibility(age: 42)
// Output
// Eligible to vote
Эту же программу можно написать с помощью оператора guard
:
func voteEligibility(age: Int) {
guard age >= 18 else {
print("Not Eligible to vote")
return
}
print("Eligible to vote")
}
// function call
voteEligibility(age: 42)
// Output
// Eligible to vote
Как видно из примера, с оператором guard
можно выйти из функции, как только условие будет оценено как ложное.
Оператор guard
удобно использовать в случае когда код необходимо выполнять только в случае, если условие выполняется, а в случае невыполнения условия - прекратить выполнение функции и выйти из нее. Например, код должен выполняться только при подключению к серверу. В противном случае - код не должен выполнятся и работа функции должна быть остановлена. Можно в этом случае использовать и оператор if
, но тогда весь код бы находился внутри блока if
. Использование guard
делает код удобнее для чтения и написания, а также помогает избежать дополнительной вложенности.
Ранний выход (Early Exit)
Инструкция guard
, как и инструкция if
, выполняет выражения в зависимости от логического значения условия. Можно использовать guard
, чтобы указать на то, что условие обязательно должно быть true
, чтобы код после самой инструкции guard
выполнился. В отличии от инструкции if
, guard
всегда имеет код внутри else
, который выполняется, когда условие оценивается как false
.
Пример:
func greet(person: [String: String]) {
guard let name = person["name"] else {
return
}
print("Hello \(name)!")
guard let location = person["location"] else {
print("I hope the weather is nice near you.")
return
}
print("I hope the weather is nice in \(location).")
}
greet(person: ["name": "John"])
// Output
// Hello John!
// I hope the weather is nice near you.
greet(person: ["name": "Jane", "location": "Cupertino"])
// Output
// Hello Jane!
// I hope the weather is nice in Cupertino.
Если условие инструкции guard
выполнилось, то выполнение кода продолжается после закрывающей скобки guard
. Все переменные и константы, которым присвоили значения с использованием опциональной привязки в качестве части условия guard
, доступны до конца области, где был определен guard
.
Если условие не выполняется, то исполняется код внутри else
. Эта ветка должна перебросить исполнение кода на выход из этого блока кода, в котором был определен guard
. А сделать это можно при помощи инструкций return
, break
, continue
, throw
или можно вызвать метод, который ничего не возвращает, например fatalError(_file:line:)
.
Использование инструкции guard
для каких-либо требований улучшает читабельность кода по сравнению с if
. Он помогает написать код, который не нужно будет помещать в блок else
и позволит держать код, который обрабатывает нарушение требований рядом с самими требованиями.
Циклы (Loops)
Для организации схем алгоритма с повторениями (циклами) в языке Swift используются операторы цикла. Есть три оператора цикла:
- Оператор цикла For-In (For-In Loops);
- Операторы цикла While (While Loops):
- Оператор цикла While;
- Оператор цикла Repeat-While.
Итерация - это повторение внутри цикла; количество итераций - количество раз, которое повторится тело цикла.
Цикл For-In (For-In Loops)
В Swift цикл for-in
используется для запуска блока кода определенное количество раз. Он используется для перебора любых последовательностей, таких как массив, диапазон, строка и т.д.
Синтаксис цикла for-in
:
for val in sequence {
// statements
}
Здесь val
обращается к каждому элементу последовательности (sequence) на каждой итерации. Цикл продолжается до тех пор, пока мы не достигнем последнего элемента в последовательности (sequence).
val
является константой и может применяться в локальной области видимости цикла - соответсвенно ее значение внутри области видимости цикла нельзя изменить. val
принимает для каждой итерации значение по очереди из последовательности.
Если значение val
внутри цикла не используется, то необходимо ее имя заменить на символ нижнего подчеркивания (_
). Например, цикл необходимо выполнить несколько раз, без применения значения данной константы:
for _ in 1...3 {
print("Hello")
}
// Output
// Hello
// Hello
// Hello
Цикл выполнился три раза - по очереди перебрались значения диапазона: 1, 2, 3.
Схема работы цикла for-in и пример использования
Пример использования:
// access items of an array
let languages = ["Swift", "Java", "Go", "JavaScript"]
for language in languages {
print(language)
}
// Output
// Swift
// Java
// Go
// JavaScript
В приведенном выше примере создали массив с именем languages
.
Изначально значение language
устанавливается как первый элемент массива, т.е. Swift
, поэтому внутри цикла выполняется функция print()
с этим значением для константы language
.
В следующей итерации language
обновляется со следующим элементом массива, и функция print()
выполняется снова. Таким образом, цикл выполняется до тех пор, пока не будет получен доступ к последнему элементу массива.
Цикл for-in с оговоркой where
В Swift также можно добавить оговорку where
с циклом for-in
. Такая конструкция используется для реализации фильтров в цикле. То есть, если условие в оговорке where
возвращает true
, тогда цикл выполняется.
Пример:
// remove Java from an array
let languages = ["Swift", "Java", "Go", "JavaScript"]
for language in languages where language != "Java"{
print(language)
}
// Output
// Swift
// Go
// JavaScript
В приведенном выше примере использовался цикл for-in
для доступа к каждому элементу languages
. Обратите внимание на использование оговорки where
в цикле for-in
:
for language in languages where language != "Java"
Здесь, если условие в оговорке where
возвращает true
, выполняется код внутри цикла. В противном случае он не выполняется.
Итерация | language | condition: != “Java” | Output |
---|---|---|---|
1 | Swift | true | Swift |
2 | Java | false | No Output |
3 | Go | true | Go |
4 | JavaScript | true | JavaScript |
Цикл for-in с диапазонами
Диапазон представляет собой ряд значений между двумя числовыми интервалами.
Например:
var values = 1...3
Здесь 1...3
определяет диапазон, содержащий значения 1, 2, 3. В Swift можно использовать цикл for-in для перебора диапазона.
Например:
// iterate from i = 1 to 1 = 3
for i in 1...3 {
print(i)
}
// Output
// 1
// 2
// 3
В приведенном выше примере мы использовали цикл for-in
для итерации в диапазоне от 1 до 3.
Значение i
устанавливается равным 1
и обновляется до следующего числа диапазона на каждой итерации. Этот процесс продолжается до тех пор, пока не будет достигнуто значение 3
.
Итерация | Условие | Действие |
---|---|---|
1 | true | печатается 1, i увеличена до 2 |
2 | true | печатается 2, i увеличена до 3 |
3 | true | печатается 3, i увеличена до 4 |
4 | false | Выполнение цикла остановлено |
Аналогично цикл работает с диапазонами, которые начинаются не с 1, а другого числа.
Примечание. Диапазон представлен числами с типом данных Int. Поскольку типы с плавающей запятой, такие как Float и Double, являются собственными типами Stride, их нельзя использовать в качестве границ счетного диапазона. Если вам нужно выполнить итерацию по последовательным значениям с плавающей запятой, см. функцию stride(from:to:by:).
Цикл for-in с функцией stride(from:to:by)
Если необходимо, чтобы цикл увеличивался на некоторое фиксированное значение на каждой итерации вместо диапазона, можно использовать функцию stride(from:to:by)
.
Например:
for i in stride(from: 1, to: 10, by: 2) {
print(i)
}
// Output
// 1
// 3
// 5
// 7
// 9
В приведенном выше примере цикл повторяется в диапазоне от 1 до 10 с интервалом 2. Однако 10 не включается в последовательность. Здесь значение i
установлено равным 1 и обновляется с интервалом 2 на каждой итерации.
Больше о функции stride(from:to:by)
можно узнать в отдельной статье. См. ссылку внизу.
Циклы While и Repeat-While
В программировании циклы используются для повторения блока кода. Например, если вы хотите показать сообщение 100 раз, вы можете использовать цикл. Это всего лишь простой пример, с помощью циклов можно добиться гораздо большего.
- Цикл While - отвечает за алгоритм цикла “Пока”;
- Цикл Repeat-While - отвечает за алгоритм цикла “До”.
Важно. В этих циклах необходимая составляющая - это блок условий выполнения цикла. Если этот блок прописать некорректно, то цикл может выполняться бесконечно. Это приведет к постоянно повышающимися затратами ресурсов и, в конечном итоге, “зависанию” программы.
Цикл While
Цикл while
используется для запуска определенного кода до тех пор, пока не будет выполнено определенное условие.
Синтаксис цикла while
:
while (condition){
// body of loop
}
Здесь,
- Цикл
while
оценивает условие внутри круглых скобок(condition)
; - Если условие оценивается как истинное (true), выполняется код внутри цикла
while
; - Состояние оценивается повторно;
- Этот процесс продолжается до тех пор, пока условие не станет ложным (false);
- Когда условие оценивается как ложное (false), цикл останавливается.
Схема работы цикла while и пример использования
Пример использования:
// program to display numbers from 1 to 5
// initialize the variable
var i = 1, n = 5
// while loop from i = 1 to 5
while (i <= n) {
print(i)
i = i + 1
}
// Output
// 1
// 2
// 3
// 4
// 5
Цикл проверяет условие i <= n
и если оно выполняется, то выполняется код в теле цикла и условие проверяется. Внутри цикла организовано изменение переменной i
- это позволяет выйти из цикла при достижении i
такого значения, когда условие цикла перестанет выполняться.
Следующий пример:
var currentLevel:Int = 0, finalLevel:Int = 5
let gameCompleted = true
while (currentLevel <= finalLevel) {
if gameCompleted {
print("You have passed level \(currentLevel)")
currentLevel += 1
}
}
print("Level Ends")
// Output
// You have passed level 0
// You have passed level 1
// You have passed level 2
// You have passed level 3
// You have passed level 4
// You have passed level 5
// Level Ends
В приведенном выше примере использовался цикл while
для проверки текущего уровня и отображения его на консоли.
Цикл Repeat-While
Цикл repeat-while
похож на цикл while
с одним ключевым отличием. Тело цикла repeat-while
выполняется один раз перед проверкой тестового выражения.
Синтаксис цикла repeat-while
:
repeat {
// body of loop
} while (condition)
Здесь,
- Сначала выполняется тело цикла. Затем оценивается состояние (condition);
- Если условие оценивается как истинное (true), тело цикла внутри оператора
repeat
выполняется снова; - Состояние (condition) оценивается еще раз;
- Этот процесс продолжается до тех пор, пока условие не станет ложным (false). Затем цикл останавливается.
Схема работы цикла repeat-while и пример использования
Пример использования:
// program to display numbers
var i = 1, n = 5
// repeat...while loop from 1 to 5
repeat {
print(i)
i = i + 1
} while (i <= n)
// Output
// 1
// 2
// 3
// 4
// 5
// 6
Цикл выполняет код внутри тела цикла и затем проверяет условие i <= n
. И если оно выполняется, то снова выполняется код в теле цикла и условие проверяется опять. Внутри цикла организовано изменение переменной i
- это позволяет выйти из цикла при достижении i
такого значения, когда условие цикла перестанет выполняться.
В отличии от цикла while
, цикл repeat-while
сначала выполняет код и затем проверяет условие. Таким образом этот цикл выполнит на одну итерацию больше, по сравнению с циклом while
.
Бесконечный цикл while
Если условие цикла while
всегда истинно, цикл выполняется бесконечное количество раз (пока не заполнится память). Это называется бесконечным циклом while.
Например:
while (true) {
print("Endless Loop")
}
// Output
// Endless Loop
// Endless Loop
// ...
// ...
// ...
Здесь условие всегда верно. Следовательно, цикл while
будет выполняться бесконечное количество раз.
Цикл for-in или цикл while
Цикл for-in
обычно используется, когда известно количество итераций.
Например:
// this loop is iterated 5 times
for number in 1...5 {
// body of loop
}
Напротив, цикл while
обычно используется, когда количество итераций неизвестно.
Например:
while (condition) {
// body of loop
}
Циклом for-in
удобнее перебирать коллекции, так как в каждой итерации сразу можно получить значение элемента коллекции. Но его так же можно заменить циклом while
.
Пример:
// access items of an array
let languages = ["Swift", "Java", "Go", "JavaScript"]
var i = 0
while i < languages.count {
print(languages[i])
i += 1
}
// Output
// Swift
// Java
// Go
// JavaScript
В этом примере доступ к элементам коллекции осуществляется через индексы.
Примечание. Работа цикла
repeat-while
такая же, как и циклаwhile
. Следовательно, он также используется, когда количество итераций неизвестно.
Вложенные циклы
Если цикл существует внутри тела другого цикла, он называется вложенным циклом. Вот пример вложенного цикла for-in
.
Пример:
// outer loop
for i in 1...5 {
// codes
// inner loop
for j in 1...2 {
//codes
}
}
Здесь внутренний цикл for j in 1...2
вложен во внешний цикл for i in 1...5
.
Вложенный цикл в цикл for-in
Вложенный цикл for-in
включает один цикл for-in
внутри другого цикла for-in
.
Например:
// Swift program to display 7 days of 2 weeks
// outer loop
for week in 1...2 {
print("Week: \(week)")
// inner loop
for day in 1...7 {
print(" Day: \(day)")
}
// line break after iteration of outer loop
print("")
}
// Output
// Week: 1
// Day: 1
// Day: 2
// ...
//
// Week: 2
// Day: 1
// Day: 2
// ...
В приведенном выше примере внешний цикл повторяется 2 раза и печатает 2 недели: Week: 1
и Week: 2
. И внутренний цикл повторяется 7 раз и печатает 7 дней: Day: 1
, Day: 2
и так далее.
Примечание. Точно так же мы можем создавать вложенные циклы
while
иrepeat-while
.Например:
// outer while loop while (condition1) { ... // inner while loop while (condition2) { ... } }
Вложенный цикл в for-in цикл while
Также можно создавать вложенные циклы разных типов. То есть можно поместить цикл for-in
внутрь цикла while
и наоборот.
Например:
// program to display 7 days of 2 weeks
var weeks = 2
var i = 1
// outer while loop
while (i <= weeks) {
print("Week: \(i)")
// inner for loop
for day in 1...7 {
print(" Day: \(day)")
}
i = i + 1
}
// Output
// Week: 1
// Day: 1
// Day: 2
// ...
//
// Week: 2
// Day: 1
// Day: 2
// ...
Здесь использовался цикл for-in
внутри цикла while
.
Примечание. Точно так же можно вложить цикл
repeat-while
внутрь циклаwhile
илиfor-in
.
Операторы передачи управления break и continue внутри вложенного цикла
1. break внутри вложенного цикла
Когда мы используем оператор break
внутри внутреннего цикла, он завершает внутренний цикл, но не внешний цикл.
Например:
// outer loop
for week in 1...3 {
print("Week: \(week)")
// inner loop
for day in 1...7 {
if (week == 2) {
// use of break statement
break
}
print(" Day: \(day)")
}
print("")
}
// Output
// Week: 1
// Day: 1
// Day: 2
// ...
//
// Week: 2
//
// Week: 3
// Day: 1
// Day: 2
// ...
В приведенном выше примере использовался оператор break
внутри внутреннего цикла for-in
.
Здесь программа завершает цикл, когда week
равна 2. Следовательно, дни week 2
не печатаются. Однако внешний цикл, который печатает неделю, не затрагивается.
2. continue внутри вложенного цикла
Точно так же, когда мы используем оператор continue
внутри внутреннего цикла, он пропускает только текущую итерацию внутреннего цикла.
Например:
// outer loop
for week in 1...2 {
print("Week: \(week)")
// inner loop
for day in 1...7 {
// use of continue statement
if (day % 2 != 0) {
continue
}
print(" Day: \(day)")
}
print("")
}
// Output
// Week: 1
// Day: 2
// Day: 4
// Day: 6
//
// Week: 2
// Day: 2
// Day: 4
// Day: 6
В приведенном выше примере использовался оператор continue
внутри внутреннего цикла for-in
.
Здесь оператор continue
выполняется, когда значение дня нечетное. Следовательно, программа печатает только четные дни. Видно, что оператор continue
затронул только внутренний цикл. Внешний цикл работает без проблем.
Операторы передачи управления (Control Transfer Statements)
Операторы передачи управления (Control Transfer Statements) меняют последовательность исполнения вашего кода, передавая управление от одного фрагмента кода другому. В Swift есть пять операторов передачи управления:
- continue;
- break;
- fallthrough;
- return;
- throw;
Операторы continue
, break
, fallthrough
описаны ниже. Оператор return
описан в статье “Функции” (см. ссылку внизу), а оператор throw
описан в статье “Передача и обработка ошибок” (см. ссылку внизу).
Оператор continue (continue Statement)
Оператор continue
используется для пропуска текущей итерации цикла, и поток управления программы переходит к следующей итерации.
Синтаксис оператора continue
следующий:
continue
Схема работы оператора continue и пример использования
Оператор continue и цикл for-in
Можно использовать оператор continue
с циклом for-in
, чтобы пропустить текущую итерацию цикла. Затем управление программой переходит к следующей итерации.
Например:
for i in 1...5 {
if i == 3 {
continue
}
print(i)
}
// Output
// 1
// 2
// 4
// 5
Здесь, когда i
равно 3
, выполняется оператор continue
. Следовательно, значение 3
не печатается на выходе.
Оператор continue и цикл while
Можно также пропустить текущую итерацию цикла while
, используя оператор continue
.
Например:
// program to print odd numbers from 1 to 10
var num = 0
while num <= 10{
num += 1
if (num % 2) == 0 {
continue
}
print("\(num)")
}
// Output
// 1
// 3
// 5
// 7
// 9
В приведенном выше примере использовали цикл while
для вывода нечетных чисел от 1 до 10.
Здесь, когда число четное, оператор continue
пропускает текущую итерацию и начинает следующую итерацию.
Оператор continue и вложенные циклы (nested loops)
Когда используем оператор continue
с вложенными циклами, он пропускает текущую итерацию внутреннего цикла.
Например:
for i in 1...3 {
for j in 1...3 {
if j == 2 {
continue
}
print("i = \(i), j = \(j)")
}
}
// Output
// i = 1, j = 1
// i = 1, j = 3
// i = 2, j = 1
// i = 2, j = 3
// i = 3, j = 1
// i = 3, j = 3
В этом примере, когда значение j
равно 2
, выполняется оператор continue
. Следовательно, значение j = 2
никогда не отображается в выходных данных.
Маркированный оператор continue (Labeled continue)
До сих пор использовался немаркированный оператор continue
. Однако в Swift есть еще одна форма оператора continue
, известная как labeled continue.
При использовании вложенных циклов мы можем пропустить текущую итерацию внешнего цикла с помощью оператора labeled continue.
Как видно на изображении выше, использовался идентификатор outerloop
внешнего цикла для указания внешнего цикла. Теперь обратите внимание, как используется оператор continue
(continue externalloop
).
Здесь оператор continue
пропускает текущую итерацию помеченного цикла (outerloop
). Затем управление программой переходит к следующей итерации помеченного цикла.
Пример Labeled continue
:
outerloop: for i in 1...3 {
innerloop: for j in 1...3 {
if j == 3 {
continue outerloop
}
print("i = \(i), j = \(j)")
}
}
// Output
// i = 1, j = 1
// i = 2, j = 1
// i = 3, j = 1
В приведенном выше примере обозначили циклы как:
- outerloop: for i in 1…3 {…};
- innerloop: for j in 1…3 {…}.
Это помогает идентифицировать петли. Обратите внимание на использование помеченного оператора continue
:
if j == 3 {
continue outerloop
}
Здесь оператор continue
пропускает итерацию внешнего цикла, помеченного как outerloop
и переходит к следующей итерации, когда значение j
равно 3
.
Примечание. Частое использование labeled continue не рекомендуется, так как это затрудняет понимание кода.
Оператор break (break Statement)
Оператор break
используется для немедленного завершения цикла при его обнаружении.
Синтаксис оператора break
следующий:
break
Схема работы оператора break и пример использования
Оператор break и цикл for-in
Можно использовать оператор break
с циклом for-in
, чтобы завершить цикл при выполнении определенного условия.
Например:
for i in 1...5 {
if i == 3 {
break
}
print(i)
}
// Output
// 1
// 2
Здесь, когда i
равно 3
, выполняется оператор break
. После этого в выводе не будет ничего после значения 2
.
Оператор break и цикл while
Можно также прекратить выполнение цикла while
, используя оператор break
.
Например:
// program to find first 5 multiples of 6
var i = 1
while (i <= 10) {
print("6 * \(i) =",6 * i)
if i >= 5 {
break
}
i = i + 1
}
// Output
// 6 * 1 = 6
// 6 * 2 = 12
// 6 * 3 = 18
// 6 * 4 = 24
// 6 * 5 = 30
В приведенном выше примере использовали цикл while
для вывода произведения первых пчти чисел и 6
.
Здесь, когда i
становиться больше 5
- выполнение цикла останавливается.
Оператор break и вложенные циклы (nested loops)
Оператор break
можно использовать с вложенными циклами:
- если использовать оператор
break
внутри внутреннего цикла, то тогда внутренний цикл останавливается; - если использовать оператор
break
снаружи внутреннего цикла, то тогда внешний цикл останавливается.
Например:
// outer for loop
for i in 1...3 {
// inner for loop
for j in 1...3 {
if i == 2 {
break
}
print("i = \(i), j = \(j)")
}
}
// Output
// i = 1, j = 1
// i = 1, j = 2
// i = 1, j = 3
// i = 3, j = 1
// i = 3, j = 2
// i = 3, j = 3
В этом примере, когда значение i
равно 2
, выполняется оператор break
. Происходит прекращение внутреннего цикла и программа переходит к следующей итерации внешнего цикла. Следовательно, значение i = 2
никогда не отображается в выходных данных.
Маркированный оператор break (Labeled break)
До сих пор использовался немаркированный оператор break
. Однако в Swift есть еще одна форма оператора break
, известная как labeled break.
При использовании вложенных циклов мы можем прекратить выполнение внешнего цикла с помощью оператора labeled break.
Как видно на изображении выше, использовался идентификатор outerloop
внешнего цикла для указания внешнего цикла. Теперь обратите внимание, как используется оператор break
(break outerloop
).
Здесь оператор break
обрывает выполнение помеченного цикла (outerloop
). Затем управление программой переходит к следующему оператору, который следует за помеченным циклом.
Пример Labeled break
:
outerloop: for i in 1...3 {
innerloop: for j in 1...3 {
if j == 3 {
break outerloop
}
print("i = \(i), j = \(j)")
}
}
// Output
// i = 1, j = 1
// i = 1, j = 2
В приведенном выше примере обозначили циклы как:
- outerloop: for i in 1…3 {…};
- innerloop: for j in 1…3 {…}.
Это помогает идентифицировать петли. Обратите внимание на использование помеченного оператора break
:
if j == 3 {
break outerloop
}
Здесь оператор break
останавливает выполнение внешнего цикла, помеченного как outerloop
и выходит из него, когда значение j
равно 3
.
Примечание. Частое использование labeled break не рекомендуется, так как это затрудняет понимание кода.
Оператор fallthrough (fallthrough Statement)
Инструкция switch
в Swift не проваливается из каждого кейса в следующий. Напротив, как только находится соответствие с первым кейсом, так сразу и прекращается работа всей инструкции.
Инструкция switch
в Swift более краткая и предсказуемая, чем она же в C, так как она предотвращает срабатывание нескольких кейсов по ошибке. В языке C, работа инструкции switch
немного сложнее, так как требует явного прекращения работы при нахождении соответствия словом break
в конце кейса. В противном случае, выполнение кода проваливается в следующий кейс и так далее пока не встретим слово break
.
Если по какой-то причине необходимо аналогичное “проваливание” как в языке C, то можно использовать оператор fallthrough
в конкретном кейсе.
Оператор fallthrough
позволяет в “провалится” в следующий кейс, даже если он не соответствует условию.
Пример:
let integerToDescribe = 5
var description = "The number \(integerToDescribe) is"
switch integerToDescribe {
case 2, 3, 5, 7, 11, 13, 17, 19:
description += " a prime number, and also"
fallthrough
default:
description += " an integer."
}
print(description)
// Output
// "The number 5 is a prime number, and also an integer."
В этом примере константа integerToDescribe
совпадает с условием кейса, поэтому программа выполняет код внутри. Потом программа встречает fallthrough
и переходит к выполнению кода в следующем блоке - default
.
Если бы константа integerToDescribe
не совпала с условием кейса, то произошел бы переход к блоку default
и выполнение его кода.
Заметка. Ключевое слово fallthrough не проверяет условие кейса, оно позволяет провалиться из конкретного кейса в следующий или в default, что совпадает со стандартным поведением инструкции switch в языке C.
Проверка доступности API (Checking API Availability)
Swift имеет встроенную поддержку проверки доступности API, что гарантирует, что вы случайно не используете API, недоступные для данной цели развертывания (deployment target).
Можно использовать условие доступности в if
или guard
инструкциях для того, чтобы условно выполнить блок кода, в зависимости от того, доступны ли API-интерфейсы, которые хотите использовать, во время выполнения. Компилятор использует информацию из условия доступности, когда проверяет доступность API-интерфейсов в этом блоке кода.
Синтаксис такой:
if #available (название платформы версия платформы, ..., * ) {
// выражения для исполнения, если соответствующие условию API доступны
} else {
// выражения для исполнения, если соответствующие условию API не доступны
}
Пример:
if #available(iOS 10, macOS 10.12, *) {
// Используйте API iOS 10 для iOS и используйте API macOS 10.12 на macOS
} else {
// Используйте более старые API для iOS и macOS
}
Условие доступности выше указывает, что на iOS тело if
выполняется только на iOS 10
и более поздних версиях; что касается macOS: только на macOS 10.12
и более поздних версиях. Последний аргумент, *
, требует и указывает, что на любой другой платформе, тело if
выполняется на минимальной указанной deployment target.
Еще полезные ссылки
Также информацию по управлению потоком можно получить на странице официальной документации.
Ссылки на официальную документацию: