Spec-Zone.ru › Swift Language

Операторы

Группируют выражения и управляют потоком выполнения.

В Swift есть три вида операторов: простые операторы, операторы управления компилятором и операторы управления потоком. Простые операторы являются наиболее распространёнными и состоят либо из выражения, либо из объявления. Операторы управления компилятором позволяют программе изменять аспекты поведения компилятора и включают в себя блок условной компиляции и оператор управления строкой.

Операторы управления потоком используются для управления потоком выполнения программы. В Swift есть несколько типов операторов управления потоком, включая операторы цикла, операторы ветвления и операторы передачи управления. Операторы цикла позволяют многократно выполнять блок кода, операторы ветвления позволяют выполнить определённый блок кода только при выполнении определённых условий, а операторы передачи управления предоставляют способ изменения порядка выполнения кода. Кроме того, Swift предоставляет оператор do для введения области действия, перехват и обработку ошибок, а также оператор defer для выполнения действий по очистке непосредственно перед выходом из текущей области действия.

Точка с запятой (;) может необязательно появляться после любого оператора и используется для разделения нескольких операторов, если они находятся на одной строке.

Грамматика оператора:

оператор → выражение ;_?_
оператор → объявление ;_?_
оператор → оператор_цикла ;_?_
оператор → оператор_ветвления ;_?_
оператор → меченый_оператор ;_?_
оператор → оператор_передачи_управления ;_?_
оператор → оператор_defer ;_?_
оператор → оператор_do ;_?_
оператор → оператор_управления_компилятором
операторы → оператор операторы_?_

Операторы цикла

Операторы цикла позволяют многократно выполнять блок кода в зависимости от условий, указанных в цикле. Swift имеет три оператора цикла: оператор цикла for-in, оператор цикла while и оператор цикла repeat-while.

Поток управления в операторе цикла может быть изменён оператором break и оператором continue и обсуждается в <doc:Statements#Break-Statement> и <doc:Statements#Continue-Statement> ниже.

Грамматика оператора цикла:

оператор_цикла → оператор_for_in
оператор_цикла → оператор_while
оператор_цикла → оператор_repeat_while

Оператор for-in

Оператор цикла for-in позволяет выполнить блок кода один раз для каждого элемента в коллекции (или любого типа), который соответствует протоколу Sequence.

Оператор цикла for-in имеет следующий вид:

for <#item#> in <#collection#> {
   <#statements#>
}

Метод makeIterator() вызывается для выражения коллекции, чтобы получить значение типа итератора — то есть, типа, который соответствует протоколу IteratorProtocol. Программа начинает выполнение цикла, вызывая метод next() для итератора. Если возвращённое значение не является nil, оно присваивается шаблону элемент, программа выполняет операторы, а затем продолжает выполнение в начале цикла. В противном случае программа не выполняет присвоение или выполнение операторов, и она завершает выполнение оператора for-in.

Грамматика оператора for-in:

оператор_for_in → for case_?_ шаблон in выражение условие_where_?_ блок_кода

Оператор while

Оператор цикла while позволяет многократно выполнять блок кода до тех пор, пока условие остаётся истинным.

Оператор цикла while имеет следующий вид:

while <#condition#> {
   <#statements#>
}

Оператор цикла while выполняется следующим образом:

  1. Вычисляется условие.

    Если true, выполнение продолжается со шага 2. Если false, программа завершает выполнение оператора цикла while.

  2. Программа выполняет операторы, и выполнение возвращается к шагу 1.

Поскольку значение условия вычисляется перед выполнением операторов, операторы в операторе цикла while могут выполняться ноль или более раз.

Значение условия должно быть типа Bool или типа, связанного с типом Bool. Условие также может быть объявлением привязки к необязательному значению, как обсуждается в <doc:TheBasics#Optional-Binding>.

Грамматика оператора while:

оператор_while → while список_условий блок_кода

список_условий → условие | условие , список_условий
условие → выражение | условие_доступности | условие_case | условие_привязки_к_необязательному_значению

условие_case → case шаблон инициализатор
условие_привязки_к_необязательному_значению → let шаблон инициализатор_?_ | var шаблон инициализатор_?_

Оператор repeat-while

Оператор цикла repeat-while позволяет выполнить блок кода один или более раз, до тех пор, пока условие остаётся истинным.

Оператор цикла repeat-while имеет следующий вид:

repeat {
   <#statements#>
} while <#condition#>

Оператор цикла repeat-while выполняется следующим образом:

  1. Программа выполняет операторы, и выполнение продолжается со шага 2.

  2. Вычисляется условие.

    Если true, выполнение возвращается к шагу 1. Если false, программа завершает выполнение оператора цикла repeat-while.

Поскольку значение условия вычисляется после выполнения операторов, операторы в операторе цикла repeat-while выполняются как минимум один раз.

Значение условия должно быть типа Bool или типа, связанного с типом Bool.

Грамматика оператора repeat-while:

оператор_repeat_while → repeat блок_кода while выражение

Операторы ветвления

Операторы ветвления позволяют программе выполнять определённые части кода в зависимости от значения одного или нескольких условий. Значения условий, указанные в операторе ветвления, управляют тем, как программа ветвится и, следовательно, какой блок кода выполняется. Swift имеет три оператора ветвления: оператор if, оператор guard и оператор switch.

Поток управления в операторе if или операторе switch может быть изменён оператором break и обсуждается в <doc:Statements#Break-Statement> ниже.

Грамматика оператора ветвления:

оператор_ветвления → оператор_if
оператор_ветвления → оператор_guard
оператор_ветвления → оператор_switch

Оператор if

Оператор if используется для выполнения кода на основе оценки одного или нескольких условий.

Существуют две основные формы оператора if. В каждой форме открывающие и закрывающие фигурные скобки обязательны.

Первая форма позволяет выполнить код только тогда, когда условие истинно и имеет следующий вид:

if <#condition#> {
   <#statements#>
}

Вторая форма оператора if предоставляет дополнительное разветвление else (введённое ключевым словом else) и используется для выполнения одной части кода, когда условие истинно, и другой части кода, когда то же самое условие ложно. Когда присутствует одно разветвление else, оператор if имеет следующий вид:

if <#condition#> {
   <#statements to execute if condition is true#>
} else {
   <#statements to execute if condition is false#>
}

Разветвление else оператора if может содержать другой оператор if для проверки нескольких условий. Последовательно связанный оператор if таким образом имеет следующий вид:

if <#condition 1#> {
   <#statements to execute if condition 1 is true#>
} else if <#condition 2#> {
   <#statements to execute if condition 2 is true#>
} else {
   <#statements to execute if both conditions are false#>
}

Значение любого условия в операторе if должно быть типа Bool или типа, связанного с типом Bool. Условие также может быть объявлением привязки к необязательному значению, как обсуждается в <doc:TheBasics#Optional-Binding>.

Грамматика оператора if:

оператор_if → if список_условий блок_кода разветвление_else_?_
разветвление_else → else блок_кода | else оператор_if

Оператор guard

Оператор guard используется для передачи управления программой из области действия, если одно или несколько условий не выполняются.

Оператор guard имеет следующий вид:

guard <#condition#> else {
   <#statements#>
}

Значение любого условия в операторе guard должно быть типа Bool или типа, связанного с типом Bool. Условие также может быть объявлением привязки к необязательному значению, как обсуждается в <doc:TheBasics#Optional-Binding>.

Любые константы или переменные, которым присвоено значение из объявления привязки к необязательному значению в условии оператора guard, могут использоваться для остальной части области действия оператора guard.

Обязательная часть (else) оператора guard должна либо вызвать функцию с типом возврата Never, либо передать управление вне области видимости оператора-защиты с помощью одного из следующих операторов:

  • return
  • break
  • continue
  • throw

Операторы передачи управления описаны в <doc:Statements#Control-Transfer-Statements> ниже. Дополнительную информацию о функциях с типом возврата Never см. в <doc:Declarations#Functions-that-Never-Return>.

Грамматика оператора-защиты:

guard-statement → guard condition-list else code-block

Оператор Switch

Оператор switch позволяет выполнять определённые блоки кода в зависимости от значения выражения управления.

Оператор switch имеет следующий вид:

switch <#control expression#> {
case <#pattern 1#>:
    <#statements#>
case <#pattern 2#> where <#condition#>:
    <#statements#>
case <#pattern 3#> where <#condition#>,
    <#pattern 4#> where <#condition#>:
    <#statements#>
default:
    <#statements#>
}

Выражение управления (control expression) оператора switch вычисляется и затем сравнивается со спецификациями, указанными в каждом случае. Если совпадение найдено, программа выполняет операторы, перечисленные в области видимости этого случая. Область видимости каждого случая не может быть пустой. В результате, вы должны включить по крайней мере один оператор после двоеточия (:) каждой метки случая. Используйте оператор одиночного break, если вы не хотите выполнять какой-либо код в теле совпавшего случая.

Значения выражений, по которым ваш код может осуществлять ветвление, очень гибкие. Например, помимо значений скалярных типов, таких как целые числа и символы, ваш код может ветвиться по значениям любого типа, включая числа с плавающей точкой, строки, кортежи, экземпляры пользовательских классов и необязательные значения. Значение выражения управления (control expression) даже может сопоставляться со значением случая в перечислении и проверяться на включение в указанный диапазон значений. Примеры использования этих различных типов значений в операторах switch см. в <doc:ControlFlow#Switch> в ControlFlow.

Случай оператора switch может необязательно содержать предложение where после каждой спецификации. Предложение «где» (where clause) вводится ключевым словом where, за которым следует выражение, и используется для предоставления дополнительного условия перед тем, как шаблон в случае считается соответствующим выражению управления (control expression). Если присутствует предложение «где» (where), операторы в соответствующем случае выполняются только в том случае, если значение выражения управления (control expression) соответствует одному из шаблонов случая и выражение предложения «где» (where) вычисляется в значение true. Например, выражение управления (control expression) соответствует случаю в примере ниже только в том случае, если это кортеж, содержащий два элемента одного и того же значения, например, (1, 1).

case let (x, y) where x == y:

Как показывает пример выше, шаблоны в случае также могут связывать константы с помощью ключевого слова let (они также могут связывать переменные с помощью ключевого слова var). Эти константы (или переменные) затем могут быть использованы в соответствующем предложении «где» (where) и во всём остальном коде в области видимости случая. Если случай содержит несколько шаблонов, которые соответствуют выражению управления, все шаблоны должны содержать одни и те же связи констант или переменных, и каждая связанная переменная или константа должна иметь один и тот же тип во всех шаблонах случая.

Оператор switch также может содержать случай по умолчанию, введённый ключевым словом default. Код внутри случая по умолчанию выполняется только в том случае, если ни один из других случаев не соответствует выражению управления.

Оператор switch может содержать только один случай по умолчанию, который должен располагаться в конце оператора switch.

Хотя фактический порядок выполнения операций сопоставления шаблонов, и в частности порядок вычисления шаблонов в случаях, не определён, сопоставление шаблонов в операторе switch ведёт себя так, как если бы вычисление выполнялось в порядке следования в исходном коде — то есть, в порядке, в котором они появляются в исходном коде. В результате, если несколько случаев содержат шаблоны, которые вычисляются до одного и того же значения, и, таким образом, могут соответствовать значению выражения управления, программа выполняет только код в первом соответствующем случае в порядке следования исходного кода.

Операторы Switch должны быть исчерпывающими

В Swift каждый возможный вариант значения выражения управления должен соответствовать значению по крайней мере одного шаблона случая. Когда это просто не выполнимо (например, когда тип выражения управления является Int), вы можете включить случай по умолчанию, чтобы удовлетворить требованию.

Переключение на будущие случаи перечисления

Незамороженное перечисление — это особый тип перечисления, которое может получить новые случаи перечисления в будущем — даже после того, как вы скомпилируете и выпустите приложение. Переключение на значения незамороженного перечисления требует дополнительного рассмотрения. Когда авторы библиотеки помечают перечисление как незамороженное, они оставляют за собой право добавить новые случаи перечисления, и любой код, который взаимодействует с этим перечислением, должен уметь обрабатывать эти будущие случаи без повторной компиляции. Код, скомпилированный в режиме эволюции библиотеки, код в стандартной библиотеке Swift, Swift-наложения для Apple-фреймворков и C- и Objective-C-код могут объявлять незамороженные перечисления. Дополнительная информация о замороженных и незамороженных перечислениях находится в <doc:Attributes#frozen>.

При переключении на значение незамороженного перечисления вам всегда необходимо включать случай по умолчанию, даже если каждый случай перечисления уже имеет соответствующий случай оператора switch. Вы можете применить атрибут @unknown к случаю по умолчанию, который указывает, что случай по умолчанию должен соответствовать только случаям перечисления, которые будут добавлены в будущем. Swift генерирует предупреждение, если случай по умолчанию соответствует любому случаю перечисления, известному на этапе компиляции. Это предупреждение о будущем информирует вас о том, что автор библиотеки добавил новый случай в перечисление, который не имеет соответствующего случая оператора switch.

В следующем примере переключаются все три существующих случая перечисления стандартной библиотеки Swift Mirror.AncestorRepresentation. Если вы добавите дополнительные случаи в будущем, компилятор сгенерирует предупреждение, чтобы указать, что вам нужно обновить оператор switch, чтобы учесть новые случаи.

let representation: Mirror.AncestorRepresentation = .generated
switch representation {
case .customized:
    print("Use the nearest ancestor’s implementation.")
case .generated:
    print("Generate a default mirror for all ancestor classes.")
case .suppressed:
    print("Suppress the representation of all ancestor classes.")
@unknown default:
    print("Use a representation that was unknown when this code was compiled.")
}
// Prints "Generate a default mirror for all ancestor classes."

Выполнение не пропускает случаи неявно

После завершения выполнения кода внутри совпавшего случая программа выходит из оператора switch. Выполнение программы не продолжается или «не пропускается» к следующему случаю или случаю по умолчанию. Тем не менее, если вы хотите, чтобы выполнение продолжалось от одного случая к следующему, явно включите оператор fallthrough, который просто состоит из ключевого слова fallthrough, в случае, из которого вы хотите продолжить выполнение. Дополнительную информацию об операторе fallthrough см. в <doc:Statements#Fallthrough-Statement> ниже.

Грамматика оператора switch:

switch-statement → switch expression { switch-cases_?_ }
switch-cases → switch-case switch-cases_?_
switch-case → case-label statements
switch-case → default-label statements
switch-case → conditional-switch-case

case-label → attributes_?_ case case-item-list :
case-item-list → pattern where-clause_?_ | pattern where-clause_?_ , case-item-list
default-label → attributes_?_ default :

where-clause → where where-expression
where-expression → expression

conditional-switch-case → switch-if-directive-clause switch-elseif-directive-clauses_?_ switch-else-directive-clause_?_ endif-directive
switch-if-directive-clause → if-directive compilation-condition switch-cases_?_
switch-elseif-directive-clauses → elseif-directive-clause switch-elseif-directive-clauses_?_
switch-elseif-directive-clause → elseif-directive compilation-condition switch-cases_?_
switch-else-directive-clause → else-directive switch-cases_?_

Оператор с меткой

Вы можете добавить метку к циклу, оператору if, оператору switch или оператору do, которая состоит из имени метки, за которым сразу следует двоеточие (:). Используйте метки операторов с операторами break и continue, чтобы явно указать, как вы хотите изменить поток управления в операторе цикла или операторе switch, как описано в <doc:Statements#Break-Statement> и <doc:Statements#Continue-Statement> ниже.

Областью видимости оператора с меткой является весь оператор, следующий за меткой оператора. Вы можете вкладывать операторы с метками, но имя каждой метки оператора должно быть уникальным.

Дополнительную информацию и примеры использования меток операторов см. в <doc:ControlFlow#Labeled-Statements> в ControlFlow.

Грамматика оператора с меткой:

labeled-statement → statement-label loop-statement
labeled-statement → statement-label if-statement
labeled-statement → statement-label switch-statement
labeled-statement → statement-label do-statement

statement-label → label-name :
label-name → identifier

Операторы передачи управления

Операторы передачи управления могут изменять порядок выполнения кода в вашей программе, безусловно передавая управление от одного фрагмента кода к другому. В Swift существует пять операторов передачи управления: оператор break, оператор continue, оператор fallthrough, оператор return и оператор throw.

Грамматика оператора передачи управления:

control-transfer-statement → break-statement
control-transfer-statement → continue-statement
control-transfer-statement → fallthrough-statement
control-transfer-statement → return-statement
control-transfer-statement → throw-statement

Оператор break

Оператор break завершает выполнение программы в цикле, операторе if или операторе switch. Оператор break может состоять только из ключевого слова break, или же из ключевого слова break, за которым следует имя метки оператора, как показано ниже.

break
break <#label name#>

Если оператор break сопровождается именем метки оператора, он завершает выполнение программы в цикле, операторе if или операторе switch, указанном этой меткой.

Если оператор break не сопровождается именем метки оператора, он завершает выполнение программы в операторе switch или внутреннем цикле, в котором он находится. Непомеченный оператор break не может использоваться для выхода из оператора if.

В обоих случаях управление передаётся на первую строку кода после окружающего цикла или оператора switch, если таковые имеются.

Примеры использования оператора break см. в <doc:ControlFlow#Break> и <doc:ControlFlow#Labeled-Statements> в ControlFlow.

Грамматика оператора break:

break-statement → break label-name_?_

Оператор continue

Оператор continue завершает выполнение текущей итерации оператора цикла, но не останавливает выполнение самого цикла. Оператор continue может состоять только из ключевого слова continue, или же из ключевого слова continue, за которым следует имя метки оператора, как показано ниже.

continue
continue <#label name#>

Если оператор continue сопровождается именем метки оператора, он завершает выполнение текущей итерации оператора цикла, указанного этой меткой.

Если оператор continue не сопровождается именем метки оператора, он завершает выполнение текущей итерации внутреннего цикла, в котором он находится.

В обоих случаях управление передаётся к условию окружающего оператора цикла.

В операторе цикла выражение инкремента всё ещё вычисляется после выполнения оператора continue, поскольку выражение инкремента вычисляется после выполнения тела цикла.

Примеры использования оператора continue см. в <doc:ControlFlow#Continue> и <doc:ControlFlow#Labeled-Statements> в ControlFlow.

Грамматика оператора continue:

continue-statement → continue label-name_?_

Оператор fallthrough

Оператор fallthrough состоит из ключевого слова fallthrough и встречается только в блоке case оператора switch. Оператор fallthrough продолжает выполнение программы от одного case в операторе switch к следующему. Выполнение программы продолжается к следующему case, даже если шаблоны меток case не соответствуют значению управляющего выражения оператора switch.

Оператор fallthrough может располагаться где угодно внутри оператора switch, а не только в качестве последнего оператора блока case, но он не может использоваться в последнем блоке case. Он также не может передать управление в блок case, шаблон которого содержит шаблоны привязки значений.

Пример использования оператора fallthrough в операторе switch см. в <doc:ControlFlow#Control-Transfer-Statements> в ControlFlow.

Грамматика оператора fallthrough:

fallthrough-statement → fallthrough

Оператор return

Оператор return используется в теле определения функции или метода и возвращает выполнение программы вызывающей функции или методу. Выполнение программы продолжается в точке сразу после вызова функции или метода.

Оператор return может состоять только из ключевого слова return, или же из ключевого слова return, за которым следует выражение, как показано ниже.

return
return <#expression#>

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

Примечание: как описано в <doc:Declarations#Failable-Initializers>, специальная форма оператора return (return nil) может использоваться в инициализаторе с возможностью ошибки для указания неудачи инициализации.

Если оператор return не сопровождается выражением, он может быть использован только для возвращения из функции или метода, не возвращающего значение (то есть, когда тип возвращаемого значения функции или метода является Void или ()).

Грамматика оператора return:

return-statement → return expression_?_

Оператор throw

Оператор throw используется в теле функции или метода, генерирующей ошибку, или в теле выражения замыкания, тип которого помечен ключевым словом throws.

Оператор throw завершает выполнение программы в текущей области видимости и начинает распространение ошибки в объёмную область. Ошибка, которая была выброшена, продолжает распространяться, пока не будет обработана в блоке catch оператора do.

Оператор throw состоит из ключевого слова throw, за которым следует выражение, как показано ниже.

throw <#expression#>

Значение выражения должно иметь тип, соответствующий протоколу Error. Если оператор do или функция, содержащая оператор throw, объявляет тип выбрасываемых ошибок, значение выражения должно быть экземпляром этого типа.

Пример использования оператора throw см. в <doc:ErrorHandling#Propagating-Errors-Using-Throwing-Functions> в ErrorHandling.

Грамматика оператора throw:

throw-statement → throw expression

Оператор defer

Оператор defer используется для выполнения кода непосредственно перед передачей управления за пределы области видимости, в которой находится оператор defer.

Оператор defer имеет следующий вид:

defer {
    <#statements#>
}

Операторы внутри оператора defer выполняются независимо от того, как происходит передача управления. Это означает, что оператор defer может использоваться, например, для управления ресурсами, такими как закрытие дескрипторов файлов, и для выполнения действий, которые должны происходить даже при возникновении ошибки.

Операторы statements в операторе defer выполняются в конце области видимости, которая включает оператор defer.

func f(x: Int) {
  defer { print("First defer") }

  if x < 10 {
    defer { print("Second defer") }
    print("End of if")
  }

  print("End of function")
}
f(x: 5)
// Prints "End of if"
// Prints "Second defer"
// Prints "End of function"
// Prints "First defer"

В приведенном коде defer в операторе if выполняется до defer, объявленной в функции f, потому что область видимости оператора if заканчивается раньше области видимости функции.

Если несколько операторов defer появляются в одной области видимости, порядок их появления — обратный порядку их выполнения. Выполнение последнего оператора defer в данной области видимости сначала означает, что операторы внутри этого последнего оператора defer могут ссылаться на ресурсы, которые будут очищены другими операторами defer.

func f() {
    defer { print("First defer") }
    defer { print("Second defer") }
    print("End of function")
}
f()
// Prints "End of function"
// Prints "Second defer"
// Prints "First defer"

Операторы в операторе defer не могут передать управление за пределы оператора defer.

Грамматика оператора defer:

defer-statement → defer code-block

Оператор do

Оператор do используется для введения новой области видимости и может содержать один или несколько операторов catch, которые содержат шаблоны, сопоставляющиеся с определёнными ошибочными условиями. Переменные и константы, объявленные в области видимости оператора do, могут быть доступны только в этой области видимости.

Оператор do в Swift похож на фигурные скобки ({}) в C, используемые для определения блока кода, и не приводит к снижению производительности во время выполнения.

Оператор do имеет следующий вид:

do {
    try <#expression#>
    <#statements#>
} catch <#pattern 1#> {
    <#statements#>
} catch <#pattern 2#> where <#condition#> {
    <#statements#>
} catch <#pattern 3#>, <#pattern 4#> where <#condition#> {
    <#statements#>
} catch {
    <#statements#>
}

Оператор do может необязательно указать тип выбрасываемой ошибки, который имеет следующий вид:

do throws(<#type#>) {
    try <#expression#>
} catch <#pattern> {
    <#statements#>
} catch {
    <#statements#>
}

Если оператор do включает оператор throws, блок do может выбрасывать ошибки только указанного типа type. Тип type должен быть конкретным типом, соответствующим протоколу Error, неявным типом, соответствующим протоколу Error, или упакованным типом протокола any Error. Если оператор do не указывает тип выбрасываемой ошибки, Swift определяет тип ошибки следующим образом:

  • Если каждое утверждение throws и выражение try в блоке кода do вложены внутри механизма обработки исчерпывающих ошибок, то Swift выводит, что утверждение do не вызывает исключений.

  • Если блок кода do содержит код, который вызывает исключения только одного типа за пределами исчерпывающей обработки ошибок, помимо вызова Never, то Swift выводит, что утверждение do вызывает этот конкретный тип ошибки.

  • Если блок кода do содержит код, который вызывает исключения более чем одного типа за пределами исчерпывающей обработки ошибок, то Swift выводит, что утверждение do вызывает any Error.

Для получения дополнительной информации о работе с ошибками, имеющими явные типы, см. <doc:ErrorHandling#Specifying-the-Error-Type>.

Если какое-либо утверждение в блоке кода do вызывает ошибку, управление программой передается первой статье catch, шаблон которой соответствует ошибке. Если ни одна из статей не соответствует, ошибка распространяется в окружающую область. Если ошибка не обрабатывается на верхнем уровне, выполнение программы останавливается с ошибкой времени выполнения.

Как и в случае с утверждением switch, компилятор пытается определить, являются ли статьи catch исчерпывающими. Если такое определение возможно, ошибка считается обработанной. В противном случае ошибка может распространяться за пределы области, содержащей эту статью, что означает, что ошибка должна быть обработана содержащей статьей catch или содержащая функция должна быть объявлена с throws.

Статья catch, имеющая несколько шаблонов, соответствует ошибке, если любой из ее шаблонов соответствует ошибке. Если статья catch содержит несколько шаблонов, все шаблоны должны содержать одни и те же связи констант или переменных, и каждая связанная переменная или константа должна иметь один и тот же тип во всех шаблонах статьи catch.

Для обеспечения обработки ошибки используйте статью catch с шаблоном, соответствующим всем ошибкам, например, шаблоном подстановки (_). Если статья catch не указывает шаблон, статья catch соответствует и связывает любую ошибку с локальной константой с именем error. Дополнительную информацию о шаблонах, которые можно использовать в статье catch, см. в разделе Шаблоны.

Чтобы увидеть пример использования утверждения do с несколькими статьями catch, см. <doc:ErrorHandling#Handling-Errors>.

Грамматика утверждения do:

do-statement → do throws-clause_?_ code-block catch-clauses_?_
catch-clauses → catch-clause catch-clauses_?_
catch-clause → catch catch-pattern-list_?_ code-block
catch-pattern-list → catch-pattern | catch-pattern , catch-pattern-list
catch-pattern → pattern where-clause_?_

Управляющие операторы компилятора

Управляющие операторы компилятора позволяют программе изменять аспекты поведения компилятора. Swift имеет три управляющих оператора компилятора: блок условной компиляции, оператор управления строкой и оператор диагностики времени компиляции.

Грамматика управляющего оператора компилятора:

compiler-control-statement → conditional-compilation-block
compiler-control-statement → line-control-statement
compiler-control-statement → diagnostic-statement

Блок условной компиляции

Блок условной компиляции позволяет условно компилировать код в зависимости от значения одного или нескольких условий компиляции.

Каждый блок условной компиляции начинается с директивы компиляции #if и заканчивается директивой компиляции #endif. Простой блок условной компиляции имеет следующий вид:

#if <#compilation condition#>
    <#statements#>
#endif

В отличие от условия оператора if, условие компиляции оценивается во время компиляции. В результате указания компилируются и выполняются только в том случае, если условие компиляции оценивается как true во время компиляции.

Условие компиляции может включать логические значения true и false, идентификатор, используемый с флагом командной строки -D, или любое из условий платформы, перечисленных в таблице ниже.

Условие платформы Допустимые аргументы
os() macOS, iOS, watchOS, tvOS, visionOS, Linux, Windows
arch() i386, x86_64, arm, arm64
swift() >= или <, за которым следует номер версии
compiler() >= или <, за которым следует номер версии
canImport() Имя модуля
targetEnvironment() simulator, macCatalyst

Номер версии для условий платформы swift() и compiler() состоит из основного номера, необязательного второстепенного номера, необязательного номер исправления и так далее, при этом точка (.) отделяет каждую часть номера версии. Между оператором сравнения и номером версии не должно быть пробелов. Версия для compiler() — это версия компилятора, независимо от параметра версии Swift, переданного компилятору. Версия для swift() — это версия языка, который в данный момент компилируется. Например, если вы компилируете свой код с помощью компилятора Swift 5 в режиме Swift 4.2, версия компилятора — 5, а версия языка — 4.2. При таких настройках приведенный ниже код выводит все три сообщения:

#if compiler(>=5)
print("Compiled with the Swift 5 compiler or later")
#endif
#if swift(>=4.2)
print("Compiled in Swift 4.2 mode or later")
#endif
#if compiler(>=5) && swift(<5)
print("Compiled with the Swift 5 compiler or later in a Swift mode earlier than 5")
#endif
// Prints "Compiled with the Swift 5 compiler or later"
// Prints "Compiled in Swift 4.2 mode or later"
// Prints "Compiled with the Swift 5 compiler or later in a Swift mode earlier than 5"

Аргумент для условия платформы canImport() — это имя модуля, который может отсутствовать на всех платформах. Имя модуля может содержать точки (.). Это условие проверяет, можно ли импортировать модуль, но фактически не импортирует его. Если модуль присутствует, условие платформы возвращает true; в противном случае — false.

Условие платформы targetEnvironment() возвращает значение true, когда код компилируется для указанной среды; в противном случае — false.

Примечание: условие платформы arch(arm) не возвращает значение true для устройств ARM 64. Условие платформы arch(i386) возвращает значение true, когда код компилируется для 32-битной симуляции iOS.

Можно комбинировать и отрицать условия компиляции с помощью логических операторов &&, || и ! и использовать скобки для группирования. Эти операторы имеют ту же ассоциативность и приоритет, что и логические операторы, используемые для объединения обычных логических выражений.

Подобно утверждению if, можно добавить несколько условных ветвей для проверки разных условий компиляции. Можно добавить любое количество дополнительных ветвей с помощью статей #elseif. Можно также добавить финальную дополнительную ветвь с помощью статьи #else. Блоки условной компиляции, содержащие несколько ветвей, имеют следующий вид:

#if <#compilation condition 1#>
    <#statements to compile if compilation condition 1 is true#>
#elseif <#compilation condition 2#>
    <#statements to compile if compilation condition 2 is true#>
#else
    <#statements to compile if both compilation conditions are false#>
#endif

Примечание: каждое утверждение в теле блока условной компиляции анализируется, даже если оно не компилируется. Однако есть исключение, если условие компиляции включает условие платформы swift() или compiler(): Утверждения анализируются только в том случае, если версия языка или компилятора соответствует тому, что указано в условии платформы. Это исключение гарантирует, что более старый компилятор не попытается проанализировать синтаксис, введенный в новой версии Swift.

Дополнительную информацию о том, как поместить явные выражения членов в блоки условной компиляции, см. в разделе <doc:Expressions#Explicit-Member-Expression>.

END_OF_DOCUMENT_MARKER

Грамматика блока условной компиляции:

conditional-compilation-block → if-directive-clause elseif-directive-clauses_?_ else-directive-clause_?_ endif-directive

if-directive-clause → if-directive compilation-condition statements_?_
elseif-directive-clauses → elseif-directive-clause elseif-directive-clauses_?_
elseif-directive-clause → elseif-directive compilation-condition statements_?_
else-directive-clause → else-directive statements_?_
if-directive → #if
elseif-directive → #elseif
else-directive → #else
endif-directive → #endif

compilation-condition → platform-condition
compilation-condition → identifier
compilation-condition → boolean-literal
compilation-condition → ( compilation-condition )
compilation-condition → ! compilation-condition
compilation-condition → compilation-condition && compilation-condition
compilation-condition → compilation-condition || compilation-condition

platform-condition → os ( operating-system )
platform-condition → arch ( architecture )
platform-condition → swift ( >= swift-version ) | swift ( < swift-version )
platform-condition → compiler ( >= swift-version ) | compiler ( < swift-version )
platform-condition → canImport ( import-path )
platform-condition → targetEnvironment ( environment )

operating-system → macOS | iOS | watchOS | tvOS | visionOS | Linux | Windows
architecture → i386 | x86_64 | arm | arm64
swift-version → decimal-digits swift-version-continuation_?_
swift-version-continuation → . decimal-digits swift-version-continuation_?_
environment → simulator | macCatalyst

Управление строками

Оператор управления строками используется для указания номера строки и имени файла, которые могут отличаться от номера строки и имени файла исходного кода, который компилируется. Используйте оператор управления строками для изменения расположения исходного кода, используемого Swift для диагностики и отладки.

Оператор управления строками имеет следующие формы:

#sourceLocation(file: <#file path#>, line: <#line number#>)
#sourceLocation()

Первая форма оператора управления строками изменяет значения литералов #line, #file, #fileID и #filePath, начиная со строки кода, следующей за оператором управления строкой. Номер строки изменяет значение #line и является любым целочисленным литералом, большим нуля. Путь к файлу изменяет значение #file, #fileID и #filePath и представляет собой строковый литерал. Указанная строка становится значением #filePath, а последняя часть пути используется значением #fileID. Сведения о #file, #fileID и #filePath см. в <doc:Expressions#Literal-Expression>.

Вторая форма оператора управления строками, #sourceLocation(), сбрасывает расположение исходного кода обратно к значениям по умолчанию для нумерации строк и пути к файлу.

Грамматика оператора управления строками:

line-control-statement → #sourceLocation ( file: file-path , line: line-number )
line-control-statement → #sourceLocation ( )
line-number → Целое десятичное число, большее нуля
file-path → static-string-literal

Оператор диагностики во время компиляции

До Swift 5.9 операторы #warning и #error генерировали диагностическое сообщение во время компиляции. Теперь это поведение обеспечивает макрос warning(_:) и error(_:) в стандартной библиотеке Swift.

Условие доступности

Условие доступности используется в качестве условия оператора if, while и guard для проверки доступности API во время выполнения на основе указанных платформ.

Условие доступности имеет следующий вид:

if #available(<#platform name#> <#version#>, <#...#>, *) {
    <#statements to execute if the APIs are available#>
} else {
    <#fallback statements to execute if the APIs are unavailable#>
}

Вы используете условие доступности для выполнения блока кода в зависимости от того, доступны ли во время выполнения API, которые вы хотите использовать. Компилятор использует информацию из условия доступности при проверке доступности API в этом блоке кода.

Условие доступности принимает список платформ и версий, разделенных запятыми. Используйте iOS, macOS, watchOS, tvOS и visionOS для имен платформ и соответствующих номеров версий. Аргумент * обязателен и указывает, что на любой другой платформе тело блока кода, защищенного условием доступности, выполняется на минимальной целевой версии, указанной в вашем проекте.

В отличие от логических условий, вы не можете комбинировать условия доступности с помощью логических операторов, таких как && и ||. Вместо использования ! для отрицания условия доступности используйте условие недоступности, которое имеет следующий вид:

if #unavailable(<#platform name#> <#version#>, <#...#>) {
    <#fallback statements to execute if the APIs are unavailable#>
} else {
    <#statements to execute if the APIs are available#>
}

Формат #unavailable является синтаксическим сахаром, который отрицает условие. В условии недоступности аргумент * является неявным и не должен включаться. Он имеет то же значение, что и аргумент * в условии доступности.

Грамматика условия доступности:

availability-condition → #available ( availability-arguments )
availability-condition → #unavailable ( availability-arguments )
availability-arguments → availability-argument | availability-argument , availability-arguments
availability-argument → platform-name platform-version
availability-argument → *

platform-name → iOS | iOSApplicationExtension
platform-name → macOS | macOSApplicationExtension
platform-name → macCatalyst | macCatalystApplicationExtension
platform-name → watchOS | watchOSApplicationExtension
platform-name → tvOS | tvOSApplicationExtension
platform-name → visionOS | visionOSApplicationExtension
platform-version → decimal-digits
platform-version → decimal-digits . decimal-digits
platform-version → decimal-digits . decimal-digits . decimal-digits

This source file is part of the Swift.org open source project
Copyright © 2014 - 2025 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API