Swift предоставляет множество операторов потока управления. Они включают в себя while
циклы для выполнения задачи несколько раз; if
, guard
И switch
заявление выполнять различные ветви коды , основанной на определенных условиях; и такие операторы, как break
и, continue
чтобы перенести поток выполнения в другую точку вашего кода.
Swift также обеспечивает for
- in
цикл , который позволяет легко перебирать массивы, словари, диапазоны, строку и другие последовательности.
switch
Утверждение Свифта значительно мощнее, чем его аналог во многих С-подобных языках. Случаи могут соответствовать множеству различных шаблонов, включая совпадения интервалов, кортежи и приведение к определенному типу. Совпадающие значения в switch
случае могут быть связаны с временными константами или переменными для использования в теле случая, и сложные условия соответствия могут быть выражены с помощью where
предложения для каждого случая.
Петли для
Вы используете цикл for
- in
для итерации последовательности, такой как элементы в массиве, диапазоны чисел или символы в строке.
В этом примере используется цикл for
- in
для перебора элементов в массиве:
let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names {
print("Hello, \(name)!")
}
// Hello, Anna!
// Hello, Alex!
// Hello, Brian!
// Hello, Jack!
Вы также можете перебирать словарь для доступа к его парам ключ-значение. Каждый элемент в словаре возвращается как кортеж, когда словарь повторяется, и вы можете разложить члены кортежа как явно названные константы для использования в теле цикла - . В приведенном ниже примере кода ключи словаря раскладываются в константу с именем , а значения словаря раскладываются в константу с именем .(key, value)
(key, value)
for
in
animalName
legCount
let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs {
print("\(animalName)s have \(legCount) legs")
}
// cats have 4 legs
// ants have 6 legs
// spiders have 8 legs
Содержимое a Dictionary
по своей природе неупорядочено, и итерации по ним не гарантируют порядок, в котором они будут получены. В частности, порядок вставки элементов в Dictionary
не определяет порядок их итерации. Для получения дополнительной информации о массивах и словарях см. Типы коллекций .
Вы также можете использовать for
- in
циклы с числовыми диапазонами. В этом примере печатаются первые несколько записей в пятикратной таблице:
for index in 1...5 {
print("\(index) times 5 is \(index * 5)")
}
// 1 times 5 is 5
// 2 times 5 is 10
// 3 times 5 is 15
// 4 times 5 is 20
// 5 times 5 is 25
Итерируемая последовательность представляет собой диапазон чисел от 1
до 5
, включительно, на что указывает использование оператора закрытого диапазона ( ...
). Значение index
устанавливается в первое число в диапазоне ( 1
), и операторы внутри цикла выполняются. В этом случае цикл содержит только одну инструкцию, которая печатает запись из пятикратной таблицы для текущего значения index
. После выполнения оператора значение index
обновляется, чтобы содержать второе значение в диапазоне ( 2
), и print(_:separator:terminator:)
функция вызывается снова. Этот процесс продолжается, пока не будет достигнут конец диапазона.
В приведенном выше примере index
это константа, значение которой автоматически устанавливается в начале каждой итерации цикла. Как таковой, index
не должен быть объявлен, прежде чем он будет использован. Он неявно объявляется просто путем включения его в объявление цикла без необходимости использования let
ключевого слова объявления.
Если вам не нужно каждое значение из последовательности, вы можете игнорировать значения, используя подчеркивание вместо имени переменной.
let base = 3
let power = 10
var answer = 1
for _ in 1...power {
answer *= base
}
print("\(base) to the power of \(power) is \(answer)")
// Prints "3 to the power of 10 is 59049"
В приведенном выше примере вычисляется значение одного числа в степени другого (в данном случае 3
в степени 10
). Он умножает начальное значение 1
(то есть 3
на степень 0
) в 3
десять раз, используя закрытый диапазон, который начинается с 1
и заканчивается на 10
. Для этого расчета отдельные значения счетчика каждый раз в цикле не нужны - код просто выполняет цикл правильное число раз. Символ подчеркивания ( _
), используемый вместо переменной цикла, вызывает игнорирование отдельных значений и не обеспечивает доступ к текущему значению во время каждой итерации цикла.
В некоторых ситуациях вы можете не захотеть использовать закрытые диапазоны, которые включают обе конечные точки. Подумайте о том, чтобы наносить отметки за каждую минуту на циферблате. Вы хотите рисовать 60
отметки, начиная с 0
минуты. Используйте оператор полуоткрытого диапазона ( ..<
), чтобы включить нижнюю границу, но не верхнюю границу. Для получения дополнительной информации о диапазонах см. Операторы диапазона .
let minutes = 60
for tickMark in 0..<minutes {
// render the tick mark each minute (60 times)
}
Некоторым пользователям может потребоваться меньше отметок в их интерфейсе. 5
Вместо этого они могли бы предпочесть одну отметку каждую минуту. Используйте stride(from:to:by:)
функцию, чтобы пропустить нежелательные метки.
let minuteInterval = 5
for tickMark in stride(from: 0, to: minutes, by: minuteInterval) {
// render the tick mark every 5 minutes (0, 5, 10, 15 ... 45, 50, 55)
}
Закрытые диапазоны также доступны, используя stride(from:through:by:)
вместо этого:
let hours = 12
let hourInterval = 3
for tickMark in stride(from: 3, through: hours, by: hourInterval) {
// render the tick mark every 3 hours (3, 6, 9, 12)
}
Пока петли
while
Цикл выполняет набор операторов , пока условие не станет false
. Такие циклы лучше всего использовать, когда число итераций неизвестно до начала первой итерации. Swift предоставляет два вида while
петель:
while
оценивает его состояние в начале каждого прохода через цикл.repeat
-while
оценивает его состояние в конце каждого прохода через цикл.
В то время как
while
Цикл начинается с вычисления одно условие. Если условие выполнено true
, набор инструкций повторяется до тех пор, пока условие не станет false
.
Вот общая форма while
цикла:
while condition {
statements
}
Этот пример играет в простую игру « Змеи и лестницы» (также известную как « Скаты и лестницы» ):
Правила игры следующие:
- Доска имеет 25 квадратов, и цель состоит в том, чтобы приземлиться на или за квадрат 25.
- Начальная клетка игрока - «квадрат ноль», который находится за левым нижним углом доски.
- Каждый ход вы бросаете шестигранный кубик и перемещаетесь на это количество квадратов, следуя горизонтальному пути, указанному пунктирной стрелкой выше.
- Если ваш ход заканчивается у основания лестницы, вы двигаетесь вверх по этой лестнице.
- Если ваш ход заканчивается во главе змеи, вы двигаетесь вниз по этой змеи.
Игровое поле представлено массивом Int
значений. Его размер основан на константе с именем finalSquare
, которая используется для инициализации массива, а также для проверки условия выигрыша позже в этом примере. Поскольку игроки начинают с доски, на «квадратном нуле» доска инициализируется 26 нулевыми Int
значениями, а не 25.
let finalSquare = 25
var board = [Int](repeating: 0, count: finalSquare + 1)
В некоторых квадратах устанавливаются более конкретные значения для змей и лестниц. Квадраты с основанием лестницы имеют положительное число, чтобы поднять вас вверх по доске, в то время как квадраты со змеиной головой имеют отрицательное число, чтобы переместить вас вниз по доске.
board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
Квадрат 3 содержит нижнюю часть лестницы, которая поднимает вас до квадрата 11. Чтобы представить это, board[03]
равен +08
, что эквивалентно целочисленному значению 8
(разница между 3
и 11
). Для выравнивания значений и операторов унарный оператор плюс ( +i
) явно используется с унарным оператором минус ( -i
) и числами ниже, чем 10
дополняются нулями. (Никакая стилистическая техника не является строго необходимой, но они приводят к более аккуратному коду.)
var square = 0
var diceRoll = 0
while square < finalSquare {
// roll the dice
diceRoll += 1
if diceRoll == 7 { diceRoll = 1 }
// move by the rolled amount
square += diceRoll
if square < board.count {
// if we're still on the board, move up or down for a snake or a ladder
square += board[square]
}
}
print("Game over!")
В приведенном выше примере используется очень простой подход к игре в кости. Вместо генерации случайного числа оно начинается со diceRoll
значения 0
. Каждый раз в while
цикле diceRoll
увеличивается на единицу, а затем проверяется, не стало ли оно слишком большим. Всякий раз, когда это возвращаемое значение равно 7
, бросок костей становится слишком большим и сбрасывается до значения 1
. Результат представляет собой последовательность diceRoll
значений, которая всегда 1
, 2
, 3
, 4
, 5
, 6
, 1
, 2
и так далее.
После броска костей игрок продвигается вперед на diceRoll
квадраты. Вполне возможно, что бросок костей переместил игрока за пределы поля 25, и в этом случае игра окончена. Чтобы справиться с этим сценарием, код проверяет, что square
меньше, чем свойство board
массива count
. Если square
он действителен, значение, сохраненное в board[square]
, добавляется к текущему square
значению, чтобы переместить игрока вверх или вниз по любым лестницам или змеям.
ЗАМЕТКА
Если эта проверка не выполняется,
board[square]
можно попытаться получить доступ к значению за пределамиboard
массива, что приведет к ошибке времени выполнения.
Затем выполнение текущего while
цикла заканчивается, и проверяется состояние цикла, чтобы увидеть, должен ли цикл быть выполнен снова. Если игрок перешел на квадратное число или за его пределы 25
, условие цикла оценивается false
и игра заканчивается.
while
Петля подходит в данном случае, так как длина игры не ясно , в начале while
цикла. Вместо этого цикл выполняется до тех пор, пока не будет выполнено определенное условие.
Repeat-While
Другой вариант while
цикла, известный как repeat
- while
цикл, сначала выполняет один проход через блок цикла, прежде чем рассмотреть условие цикла. Затем он продолжает повторять цикл, пока не будет выполнено условие false
.
ЗАМЕТКА
repeat
-while
петля в Swift аналогичнаdo
-while
петли на других языках.
Вот общая форма цикла repeat
- while
:
repeat {
statements
} while condition
Вот Змеи и лестницы пример еще раз, записывается в виде repeat
- while
петли , а не while
петли. Значения finalSquare
, board
, square
и diceRoll
инициализируются точно таким же образом , как и с while
петлей.
let finalSquare = 25
var board = [Int](repeating: 0, count: finalSquare + 1)
board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
var square = 0
var diceRoll = 0
В этой версии игры первым действием в цикле является проверка на наличие лестницы или змеи. Никакая лестница на игровом поле не приводит игрока прямо к клетке 25, и поэтому невозможно выиграть игру, поднявшись по лестнице. Следовательно, в качестве первого действия в цикле безопасно проверить наличие змеи или лестницы.
В начале игры игрок находится на «квадрате ноль». board[0]
всегда равно 0
и не имеет никакого эффекта.
repeat {
// move up or down for a snake or ladder
square += board[square]
// roll the dice
diceRoll += 1
if diceRoll == 7 { diceRoll = 1 }
// move by the rolled amount
square += diceRoll
} while square < finalSquare
print("Game over!")
После того, как код проверяет наличие змей и лестниц, игра в кости бросается, и игрок продвигается вперед на diceRoll
квадраты. Выполнение текущего цикла затем заканчивается.
Условие цикла ( ) такое же, как и раньше, но на этот раз оно не оценивается до концапервого цикла цикла. Структура - петли лучше подходит к этой игре , чем цикл в предыдущем примере. В - петли выше, всегда выполняется сразу же после того, как Петля в состояние подтверждает , что все еще находится на борту. Такое поведение устраняет необходимость в проверке границ массива, которую можно увидеть в циклической версии игры, описанной ранее.while square < finalSquare
repeat
while
while
repeat
while
square += board[square]
while
square
while
Условные заявления
Часто полезно выполнять разные фрагменты кода в зависимости от определенных условий. Возможно, вы захотите запустить дополнительный фрагмент кода при возникновении ошибки или отобразить сообщение, когда значение становится слишком высоким или слишком низким. Для этого вы делаете части своего кода условными .
Swift предоставляет два способа добавления условных переходов в ваш код: if
оператор и switch
оператор. Как правило, вы используете if
оператор для оценки простых условий с несколькими возможными результатами. Оператор switch
лучше подходит для более сложных условий с множеством возможных перестановок и полезен в ситуациях, когда сопоставление с образцом может помочь выбрать подходящую ветвь кода для выполнения.
Если
В простейшей форме if
утверждение имеет единственное if
условие. Он выполняет набор операторов, только если это условие true
.
var temperatureInFahrenheit = 30
if temperatureInFahrenheit <= 32 {
print("It's very cold. Consider wearing a scarf.")
}
// Prints "It's very cold. Consider wearing a scarf."
В приведенном выше примере проверяется, является ли температура меньше или равна 32 градусам Фаренгейта (точка замерзания воды). Если это так, сообщение печатается. В противном случае сообщение не печатается, и выполнение кода продолжается после if
закрывающей скобки оператора.
if
Оператор может обеспечить альтернативный набор операторов, известные как п - либо , для ситуаций , когда if
условие false
. Эти заявления обозначены else
ключевым словом.
temperatureInFahrenheit = 40
if temperatureInFahrenheit <= 32 {
print("It's very cold. Consider wearing a scarf.")
} else {
print("It's not that cold. Wear a t-shirt.")
}
// Prints "It's not that cold. Wear a t-shirt."
Одна из этих двух веток всегда выполняется. Поскольку температура повысилась до 40
градусов по Фаренгейту, уже недостаточно холодно, чтобы рекомендовать носить шарф, и else
вместо этого срабатывает ветвь.
Вы можете связать несколько if
операторов вместе, чтобы рассмотреть дополнительные предложения.
temperatureInFahrenheit = 90
if temperatureInFahrenheit <= 32 {
print("It's very cold. Consider wearing a scarf.")
} else if temperatureInFahrenheit >= 86 {
print("It's really warm. Don't forget to wear sunscreen.")
} else {
print("It's not that cold. Wear a t-shirt.")
}
// Prints "It's really warm. Don't forget to wear sunscreen."
Здесь if
было добавлено дополнительное заявление, чтобы ответить на особенно теплые температуры. Последний else
пункт остается, и он печатает ответ для любых температур, которые не являются ни слишком теплыми, ни слишком холодными.
Однако последний else
пункт является необязательным и может быть исключен, если набор условий не требуется выполнять.
temperatureInFahrenheit = 72
if temperatureInFahrenheit <= 32 {
print("It's very cold. Consider wearing a scarf.")
} else if temperatureInFahrenheit >= 86 {
print("It's really warm. Don't forget to wear sunscreen.")
}
Поскольку температура не слишком низкая и не слишком высокая, чтобы вызвать условия if
или , сообщение не печатается.else if
переключатель
switch
Заявление рассматривает значение и сравнивает его с нескольких возможных моделей соответствия. Затем он выполняет соответствующий блок кода на основе первого шаблона, который успешно соответствует. switch
Заявление предоставляет альтернативу if
заявления для реагирования на несколько возможных состояний.
В своей простейшей форме switch
оператор сравнивает значение с одним или несколькими значениями одного и того же типа.
switch some value to consider {
case value 1:
respond to value 1
case value 2,
value 3:
respond to value 2 or 3
default:
otherwise, do something else
}
Каждое switch
утверждение состоит из нескольких возможных случаев , каждый из которых начинается с case
ключевого слова. В дополнение к сравнению с конкретными значениями, Swift предоставляет несколько способов для каждого случая, чтобы указать более сложные шаблоны сопоставления. Эти параметры описаны ниже в этой главе.
Как и тело if
оператора, каждый case
является отдельной ветвью выполнения кода. switch
Оператор определяет , какая ветвь должна быть выбрана. Эта процедура называется включением значения, которое рассматривается.
Каждое switch
утверждение должно быть исчерпывающим . То есть каждое возможное значение рассматриваемого типа должно соответствовать одному из switch
случаев. Если не уместно указывать регистр для каждого возможного значения, вы можете определить регистр по умолчанию, чтобы охватить любые значения, которые не адресованы явно. Этот регистр по умолчанию обозначается default
ключевым словом и всегда должен быть последним.
В этом примере используется switch
инструкция для рассмотрения одного символа нижнего регистра someCharacter
:
let someCharacter: Character = "z"
switch someCharacter {
case "a":
print("The first letter of the alphabet")
case "z":
print("The last letter of the alphabet")
default:
print("Some other character")
}
// Prints "The last letter of the alphabet"
В switch
первом сазе совпадает с первой буквой английского алфавита, a
и его второй случай соответствует последней букве z
. Поскольку switch
аргумент должен иметь регистр для каждого возможного символа, а не только для каждого буквенного символа, этот switch
оператор использует default
регистр для сопоставления всех символов, кроме a
и z
. Это положение гарантирует, что switch
заявление является исчерпывающим.
Нет неявного падения
В отличие от switch
операторов в C и Objective-C, switch
операторы в Swift по умолчанию не попадают в нижнюю часть каждого случая и попадают в следующий. Вместо этого весь switch
оператор завершает свое выполнение, как только завершается первый соответствующий switch
случай, не требуя явного break
оператора. Это делает switch
инструкцию более безопасной и простой в использовании, чем в Си, и позволяет избежать выполнения более одного switch
случая по ошибке.
ЗАМЕТКА
Хотя
break
это не требуется в Swift, вы можете использоватьbreak
оператор для сопоставления и игнорирования конкретного случая или выхода из сопоставленного случая до того, как этот случай завершит свое выполнение. Для получения дополнительной информации см. Разрыв в операторе переключения .
Тело каждого случая должно содержать хотя бы один исполняемый оператор. Недопустимо писать следующий код, потому что первый случай пуст:
let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a": // Invalid, the case has an empty body
case "A":
print("The letter A")
default:
print("Not the letter A")
}
// This will report a compile-time error.
В отличие от switch
оператора в C, это switch
утверждение не соответствует как "a"
и "A"
. Скорее, он сообщает об ошибке времени компиляции, которая не содержит никаких исполняемых операторов. Этот подход позволяет избежать случайного падения из одного случая в другой и обеспечивает более безопасный код, более понятный по своему замыслу.case "a":
Чтобы создать switch
с одним регистром, который соответствует обоим "a"
и "A"
, объедините два значения в составной регистр, разделяя значения запятыми.
let anotherCharacter: Character = "a"
switch anotherCharacter {
case "a", "A":
print("The letter A")
default:
print("Not the letter A")
}
// Prints "The letter A"
Для удобства чтения составной регистр также может быть записан в несколько строк. Для получения дополнительной информации о составных случаях см. Составные случаи .
ЗАМЕТКА
Чтобы явно провалиться в конце конкретного
switch
случая, используйтеfallthrough
ключевое слово, как описано в Fallthrough .
Интервал соответствия
Значения в switch
случаях можно проверить на предмет их включения в интервал. В этом примере используются числовые интервалы для обеспечения счета на естественном языке для чисел любого размера:
let approximateCount = 62
let countedThings = "moons orbiting Saturn"
let naturalCount: String
switch approximateCount {
case 0:
naturalCount = "no"
case 1..<5:
naturalCount = "a few"
case 5..<12:
naturalCount = "several"
case 12..<100:
naturalCount = "dozens of"
case 100..<1000:
naturalCount = "hundreds of"
default:
naturalCount = "many"
}
print("There are \(naturalCount) \(countedThings).")
// Prints "There are dozens of moons orbiting Saturn."
В приведенном выше примере, approximateCount
оценивается в switch
заявлении. Каждый case
сравнивает это значение с числом или интервалом. Поскольку значение approximateCount
падает между 12 и 100, naturalCount
присваивается значение , и исполнение переносится из оператора."dozens of"
switch
Кортеж
Вы можете использовать кортежи для проверки нескольких значений в одном switch
выражении. Каждый элемент кортежа может быть проверен по разному значению или интервалу значений. В качестве альтернативы используйте символ подчеркивания ( _
), также известный как шаблон подстановки, для сопоставления с любым возможным значением.
В приведенном ниже примере берется точка (x, y), выраженная в виде простого кортежа типа , и она классифицируется на графике, который следует за примером.(Int, Int)
let somePoint = (1, 1)
switch somePoint {
case (0, 0):
print("\(somePoint) is at the origin")
case (_, 0):
print("\(somePoint) is on the x-axis")
case (0, _):
print("\(somePoint) is on the y-axis")
case (-2...2, -2...2):
print("\(somePoint) is inside the box")
default:
print("\(somePoint) is outside of the box")
}
// Prints "(1, 1) is inside the box"
switch
Утверждение определяет , находится ли точка находится в начале координат (0, 0), на красной оси х, на оранжевой оси у, внутри синей коробке 4-на-4 с центром в начале координат, или вне коробки.
В отличие от C, Swift позволяет нескольким switch
случаям рассматривать одно и то же значение или значения. Фактически, точка (0, 0) может соответствовать всем четыремслучаям в этом примере. Однако, если возможно несколько совпадений, всегда используется первый случай совпадения. Точка (0, 0) будет соответствовать первой, и поэтому все другие соответствующие случаи будут игнорироваться.case (0, 0)
Привязки значений
switch
Случай может назвать значение или значение , что соответствует временным константам или переменным, для использования в теле корпуса. Такое поведение известно как привязка значений , поскольку значения привязаны к временным константам или переменным в теле кейса.
В приведенном ниже примере берется точка (x, y), выраженная в виде кортежа типа , и она классифицируется на следующем графике:(Int, Int)
let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0):
print("on the x-axis with an x value of \(x)")
case (0, let y):
print("on the y-axis with a y value of \(y)")
case let (x, y):
print("somewhere else at (\(x), \(y))")
}
// Prints "on the x-axis with an x value of 2"
switch
Утверждение определяет , находится ли точка на красной оси х, на оранжевой оси у, или в другом месте (на оси ни).
В трех switch
случаях объявляются константы-заполнители x
и y
, которые временно принимают одно или оба значения кортежа из anotherPoint
. В первом случае, соответствует любой точке со значением и присваивает значение точки временной константе . Аналогично, второй случай, сопоставляет любую точку со значением и присваивает значение точки временной константе .case (let x, 0)
y
0
x
x
case (0, let y)
x
0
y
y
После того, как временные константы объявлены, они могут использоваться в блоке кода дела. Здесь они используются для печати категоризации точки.
Это switch
утверждение не имеет default
дела. В последнем случае объявляется кортеж из двух констант-заполнителей, которые могут соответствовать любому значению. Поскольку это всегда кортеж из двух значений, этот регистр соответствует всем возможным оставшимся значениям, и регистр не требуется для того, чтобы сделать инструкцию исчерпывающей.case let (x, y)
anotherPoint
default
switch
куда
switch
Случай можно использовать where
пункт для проверки дополнительных условий.
Пример ниже классифицирует точку (x, y) на следующем графике:
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")
}
// Prints "(1, -1) is on the line x == -y"
switch
Оператор определяет , находится ли точка находится на зеленой диагональной линии , где на фиолетовом диагональной линии , где , или ни.x == y
x == -y
В трех switch
случаях объявляются константы-заполнители x
и y
, которые временно принимают два значения кортежа из yetAnotherPoint
. Эти константы используются как часть where
предложения для создания динамического фильтра. switch
Случай соответствует текущему значению , point
только если where
условие вычисляется Морозом , чтобы true
для этого значения.
Как и в предыдущем примере, окончательный регистр соответствует всем возможным оставшимся значениям, поэтому default
регистр не требуется, чтобы сделать switch
инструкцию исчерпывающей.
Сложные случаи
Несколько вариантов переключения, которые имеют одно и то же тело, можно объединить, написав несколько шаблонов после case
, с запятой между каждым из шаблонов. Если какой-либо шаблон соответствует, то случай считается соответствующим. Шаблоны могут быть записаны в несколько строк, если список длинный. Например:
let someCharacter: Character = "e"
switch someCharacter {
case "a", "e", "i", "o", "u":
print("\(someCharacter) is a vowel")
case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
"n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
print("\(someCharacter) is a consonant")
default:
print("\(someCharacter) is not a vowel or a consonant")
}
// Prints "e is a vowel"
В switch
первом сазе совпадает все пять строчных гласных в английском языке. Аналогично, его второй регистр соответствует всем строчным английским согласным. Наконец, default
регистр соответствует любому другому символу.
Сложные случаи также могут включать привязки значений. Все шаблоны составного случая должны включать в себя один и тот же набор привязок значений, и каждая привязка должна получать значение одного и того же типа из всех шаблонов в составном случае. Это гарантирует, что независимо от того, какая часть составного случая совпадает, код в теле случая всегда может получить доступ к значению для привязок, и что значение всегда имеет один и тот же тип.
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")
}
// Prints "On an axis, 9 from the origin"
case
Выше , имеет две модели: совпадения точек на оси х и соответствует точек на оси у. Оба шаблона включают в себя привязку и являются целым числом в обоих шаблонах, что означает, что код в теле может всегда иметь доступ к значению для .(let distance, 0)
(0, let distance)
distance
distance
case
distance
Заявления о передаче управления
Операторы передачи управления изменяют порядок, в котором выполняется ваш код, путем передачи управления от одного фрагмента кода к другому. Swift имеет пять операторов передачи управления:
continue
break
fallthrough
return
throw
Операторы continue
, break
и fallthrough
описаны ниже. Оператор return
описан в разделе « Функции» , а throw
оператор - в разделе « Распространение ошибок с использованием бросающих функций» .
Продолжить
continue
Оператор говорит цикл , чтобы остановить то , что он делает , и начать снова в начале следующей итерации цикла. Он говорит: «Я закончил с текущей итерацией цикла», не выходя из цикла вообще.
В следующем примере удаляются все гласные и пробелы из строчной строки для создания загадочной фразы-головоломки:
let puzzleInput = "great minds think alike"
var puzzleOutput = ""
let charactersToRemove: [Character] = ["a", "e", "i", "o", "u", " "]
for character in puzzleInput {
if charactersToRemove.contains(character) {
continue
}
puzzleOutput.append(character)
}
print(puzzleOutput)
// Prints "grtmndsthnklk"
Приведенный выше код вызывает continue
ключевое слово всякий раз, когда оно соответствует гласному или пробелу, в результате чего текущая итерация цикла немедленно завершается и переходит прямо к началу следующей итерации.
Перерыв
break
Оператор заканчивается выполнение всего отчета о движении управления немедленно. break
Заявление может быть использовано внутри switch
оператора или цикла , когда вы хотите прервать выполнение switch
оператора или цикла раньше , чем было бы в противном случае.
Перерыв в цикле
При использовании внутри инструкции break
цикла немедленно завершает выполнение цикла и передает управление коду после закрывающей скобки цикла ( }
). Никакой дополнительный код из текущей итерации цикла не выполняется, и дальнейшие итерации цикла не запускаются.
Перерыв в операторе переключения
При использовании внутри switch
оператора break
заставляет switch
оператор немедленно завершать его выполнение и передавать управление в код после switch
закрывающей скобки оператора ( }
).
Это поведение можно использовать для сопоставления и игнорирования одного или нескольких случаев в switch
выражении. Поскольку switch
утверждение Свифта является исчерпывающим и не допускает пустых падежей, иногда необходимо преднамеренно сопоставлять и игнорировать регистр, чтобы сделать ваши намерения явными. Вы делаете это, записывая break
заявление как весь текст дела, которое хотите игнорировать. Когда этот случай совпадает с switch
оператором, break
оператор внутри случая switch
немедленно завершает выполнение оператора.
ЗАМЕТКА
switch
Случай , который содержит только комментарий сообщается как ошибка времени компиляции. Комментарии не являются заявлениями и не приводят switch
к игнорированию дела. Всегда используйте break
оператор, чтобы игнорировать switch
регистр.
В следующем примере включается Character
значение и определяется, представляет ли оно символ числа на одном из четырех языков. Для краткости несколько значений рассматриваются в одном switch
случае.
let numberSymbol: Character = "三" // Chinese symbol for the number 3
var possibleIntegerValue: Int?
switch numberSymbol {
case "1", "١", "一", "๑":
possibleIntegerValue = 1
case "2", "٢", "二", "๒":
possibleIntegerValue = 2
case "3", "٣", "三", "๓":
possibleIntegerValue = 3
case "4", "٤", "四", "๔":
possibleIntegerValue = 4
default:
break
}
if let integerValue = possibleIntegerValue {
print("The integer value of \(numberSymbol) is \(integerValue).")
} else {
print("An integer value could not be found for \(numberSymbol).")
}
// Prints "The integer value of 三 is 3."
Этот пример проверяет , numberSymbol
чтобы определить , является ли это латинский, арабский, китайский, тайский или символ для чисел 1
до 4
. Если совпадение найдено, один из switch
случаев оператора устанавливает необязательную Int?
переменную, вызываемую possibleIntegerValue
для соответствующего целочисленного значения.
После того, как switch
инструкция завершает свое выполнение, пример использует необязательную привязку, чтобы определить, было ли найдено значение. possibleIntegerValue
Переменная имеет неявный начальное значение nil
в силу того , необязательный тип, и поэтому дополнительное связывание будет успешным , только если possibleIntegerValue
был установлен на фактическое значение одного из switch
Заявление о первых четырех случаях.
Поскольку перечислять все возможные Character
значения в приведенном выше примере нецелесообразно , default
регистр обрабатывает любые символы, которые не совпадают. В этом default
случае не требуется выполнять какие-либо действия, поэтому он записывается с одним break
оператором в качестве тела. Как только default
сопоставляется регистр, break
оператор завершает выполнение switch
оператора, и выполнение кода продолжается с оператора.if let
Провалиться
В Swift switch
операторы не попадают в нижнюю часть каждого дела и переходят к следующему. Таким образом, весь switch
оператор завершает свое выполнение, как только первый соответствующий случай завершен. В отличие от этого, C требует, чтобы вы вставляли явное break
утверждение в конце каждого switch
случая, чтобы предотвратить падение. Предотвращение падения по умолчанию означает, что switch
операторы Swift намного более кратки и предсказуемы, чем их аналоги в C, и, таким образом, они избегают выполнения нескольких switch
случаев по ошибке.
Если вам нужно поведение при падении в стиле 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)
// Prints "The number 5 is a prime number, and also an integer."
В этом примере объявляется новая String
переменная с именем description
и присваивается ей начальное значение. Затем функция рассматривает значение integerToDescribe
использования switch
оператора. Если значение integerToDescribe
является одним из простых чисел в списке, функция добавляет текст в конец description
, чтобы отметить, что число является простым. Затем он также использует fallthrough
ключевое слово, чтобы «попасть в» default
дело. default
Случай добавляет дополнительный текст в конце описания, и switch
утверждение завершено.
Если значение не integerToDescribe
находится в списке известных простых чисел, оно вообще не соответствует первому switch
случаю. Потому что нет никаких других конкретных случаев, integerToDescribe
соответствует default
делу.
После того, как switch
оператор завершил выполнение, описание номера печатается с использованием print(_:separator:terminator:)
функции. В этом примере число 5
правильно идентифицируется как простое число.
ЗАМЕТКА
fallthrough
Ключевое слово не проверяет условия случае дляswitch
случая , что вызывает исполнение впасть в.fallthrough
Ключевое слово просто вызывает выполнение кода , чтобы перейти непосредственно к высказываниям внутри следующий случай (илиdefault
случай) блока, как и в стандартном C вswitch
поведении операторов.
Помеченные заявления
В Swift вы можете вкладывать циклы и условные операторы в другие циклы и условные операторы для создания сложных структур потока управления. Однако циклы и условные операторы могут использовать break
оператор для преждевременного завершения выполнения. Следовательно, иногда полезно явно указать, какой цикл или условный оператор вы хотите break
завершить. Точно так же, если у вас есть несколько вложенных циклов, может быть полезно четко указать, на какой цикл continue
должен влиять оператор.
Для достижения этих целей вы можете пометить оператор цикла или условный оператор меткой оператора . С условным оператором вы можете использовать метку оператора с break
оператором, чтобы завершить выполнение помеченного оператора. С оператором цикла вы можете использовать метку оператора с оператором break
или, continue
чтобы завершить или продолжить выполнение помеченного оператора.
Помеченный оператор указывается путем размещения метки в той же строке, что и ключевое слово вводителя оператора, за которым следует двоеточие. Вот пример этого синтаксиса для while
цикла, хотя принцип одинаков для всех циклов и switch
операторов:
label name: while condition {
statements
}
В следующем примере используется break
и continue
операторы с меченой while
петлей для адаптированной версии Змеи и лестницы игры , которые вы видели ранее в этой главе. На этот раз в игре есть дополнительное правило:
- Чтобы выиграть, вы должны приземлиться ровно на 25 клетке.
Если конкретный бросок костей выведет вас за пределы квадрата 25, вы должны бросить снова, пока вы не бросите точное число, необходимое для посадки на клетку 25.
Игровая доска такая же, как и раньше.
Значения finalSquare
, board
, square
и diceRoll
инициализируются таким же образом , как и раньше:
let finalSquare = 25
var board = [Int](repeating: 0, count: finalSquare + 1)
board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
var square = 0
var diceRoll = 0
Эта версия игры использует while
цикл и switch
оператор для реализации логики игры. while
Цикл имеет метку заявления под названием , gameLoop
чтобы указать , что основной цикл игры для игры Змеи и лестницы.
В while
условии цикла является , чтобы отразить , что вы должны точно приземлиться на площади 25.while square != finalSquare
gameLoop: while square != finalSquare {
diceRoll += 1
if diceRoll == 7 { diceRoll = 1 }
switch square + diceRoll {
case finalSquare:
// diceRoll will move us to the final square, so the game is over
break gameLoop
case let newSquare where newSquare > finalSquare:
// diceRoll will move us beyond the final square, so roll again
continue gameLoop
default:
// this is a valid move, so find out its effect
square += diceRoll
square += board[square]
}
}
print("Game over!")
Кости бросаются в начале каждого цикла. Вместо того, чтобы немедленно перемещать игрока, цикл использует switch
инструкцию, чтобы рассмотреть результат хода и определить, разрешен ли ход:
- Если бросок костей переместит игрока на последний квадрат, игра окончена. В передает заявление управления в первой строке кода за пределами цикла, который заканчивает игру.
break gameLoop
while
- Если бросок костей переместит игрока за пределы последнего квадрата, ход будет недействительным, и игрок должен снова бросить. Оператор завершает текущую итерацию цикла и начинает следующую итерацию цикла.
continue gameLoop
while
- Во всех других случаях бросок костей является допустимым ходом. Игрок продвигается вперед на
diceRoll
квадраты, а логика игры проверяет наличие змей и лестниц. Затем цикл заканчивается, и управление возвращается кwhile
условию, чтобы решить, требуется ли еще один оборот.
ЗАМЕТКА
Если в break
вышеприведенном утверждении не используется gameLoop
метка, то оно вырвется из switch
утверждения, а не из while
утверждения. Использование gameLoop
метки дает понять, какой оператор управления должен быть завершен.
Нет необходимости использовать gameLoop
метку при вызове для перехода к следующей итерации цикла. В игре только один цикл, и, следовательно, нет двусмысленности относительно того, на какой цикл повлияет это утверждение. Однако использование ярлыка с заявлением не повредит . Это согласуется с использованием ярлыка вместе с утверждением и помогает сделать логику игры более понятной для чтения и понимания.continue gameLoop
continue
gameLoop
continue
break
Ранний выход
guard
Заявление, как if
заявление, выполняет операторы в зависимости от логического значения выражения. Вы используете guard
оператор, чтобы требовать, чтобы условие было истинным, чтобы код после guard
оператора был выполнен. В отличие от if
оператора, guard
оператор всегда имеет else
предложение - код внутри else
предложения выполняется, если условие не выполняется.
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"])
// Prints "Hello John!"
// Prints "I hope the weather is nice near you."
greet(person: ["name": "Jane", "location": "Cupertino"])
// Prints "Hello Jane!"
// Prints "I hope the weather is nice in Cupertino."
Если guard
условие оператора выполнено, выполнение кода продолжается после guard
закрывающей скобки оператора. Любые переменные или константы, которым были присвоены значения с использованием необязательной привязки как части условия, доступны для остальной части блока кода, в guard
котором появляется инструкция.
Если это условие не выполняется, выполняется код внутри else
ветви. Эта ветвь должна передать управление, чтобы выйти из блока кода, в котором guard
появляется инструкция. Он может сделать это с заявлением передачи управления , например return
, break
, continue
, или throw
, или это может вызвать функцию или метод , который не возвращается, такие как fatalError(_:file:line:)
.
Использование guard
оператора для требований улучшает читабельность вашего кода по сравнению с выполнением той же проверки с if
оператором. Он позволяет вам писать код, который обычно выполняется, не заключая его в else
блок, и позволяет хранить код, который обрабатывает нарушенное требование, рядом с требованием.
Проверка доступности API
Swift имеет встроенную поддержку для проверки доступности API, которая гарантирует, что вы не будете случайно использовать API, которые недоступны для данной цели развертывания.
Компилятор использует информацию о доступности в SDK, чтобы убедиться, что все API-интерфейсы, используемые в вашем коде, доступны для цели развертывания, указанной вашим проектом. Swift сообщает об ошибке во время компиляции, если вы пытаетесь использовать API, который недоступен.
Вы используете условие доступности в операторе if
или guard
для условного выполнения блока кода в зависимости от того, доступны ли API, которые вы хотите использовать, во время выполнения. Компилятор использует информацию из условия доступности, когда он проверяет, что API в этом блоке кода доступны.
if #available(iOS 10, macOS 10.12, *) {
// Use iOS 10 APIs on iOS, and use macOS 10.12 APIs on macOS
} else {
// Fall back to earlier iOS and macOS APIs
}
Приведенное выше условие доступности указывает, что в iOS тело if
инструкции выполняется только в iOS 10 и более поздних версиях; в macOS, только в macOS 10.12 и выше. Последний аргумент, *
является обязательным и указывает, что на любой другой платформе тело if
исполняется с минимальной целью развертывания, указанной вашей целью.
В общем виде условие доступности принимает список названий и версий платформ. Вы можете использовать название платформы , такие как iOS
, macOS
, watchOS
, и tvOS
-дль полного списка см Декларации атрибутов . В дополнение к указанию основных номеров версий, таких как iOS 8 или macOS 10.10, вы можете указать дополнительные номера версий, таких как iOS 11.2.6 и macOS 10.13.3.
if #available(platform name version, ..., *) {
statements to execute if the APIs are available
} else {
fallback statements to execute if the APIs are unavailable
}
0 комментариев