Link Search Menu Expand Document

Базові оператори

Оператор - це спеціальний символ або фраза, що вживається для перевірки, зміни чи об’єднання значень. Наприклад, оператор додавання (+) додає два числа, як let i = 1 + 2, і оператор логічного “і” (&&) об’єднує два булевих значення, як if enteredDoorCode && passedRetinaScan.

Мова Swift підтримує більшість стандартних операторів мови C та покращує можливості деяких із них, щоб позбутись типових помилок програмування. Оператор присвоєння (=) не повертає значення, щоб не допустити його випадкове вживання замість оператора порівняння (==). Арифметичні оператори (+, -, *, /, % і так далі) виявляють і не допускають переповнення значення, щоб уникнути
неочікуваних результатів під час роботи з числами, що стають більшими чи меншими, ніж найбільше чи найменше значення з діапазону значень типу, що їх зберігають. Переповнення змінних можна увімкнути за допомогою операторів переповнення мови Swift, як описано в розділі Оператори переповнення.

Мова Swift також надає два оператори діапазонів (a..<b та a...b), котрих нема у мові C, як скорочення для оголошення діапазону значень.

Даний розділ описує типові оператори у мові Swift. Розділ Розширені оператори покриває розширені оператори мови Swift, а також описує способи створення власних операторів та реалізації стандартних операторів для власних типів.

Термінологія

Оператори бувають унарні, бінарні та тернарні:

  • Унарні оператори оперують єдиним операндом (наприклад, -a). Унарні префіксні оператори ставляться безпосередньо перед їх операндами (наприклад, !b), а унарні постфіксні оператори ставляться безпосередньо після їх операндів (наприклад, c!).
  • Бінарні оператори оперують двома операндами (наприклад, 2 + 3), і є інфіксними, бо вони ставляться між їх операндами.
  • Тернарні оператори оперують трьома операндами. Як і мова C, Swift має лише один тернарний оператор, тернарний умовний оператор (a ? b : c).

Значення, на які діє оператор, називаються операндами. У виразі 1 + 2, символ + є бінарним оператором, а його операндами є значення 1 і 2.

Оператор присвоєння

Оператор присвоєння (a = b) ініціалізує чи оновлює значення a значенням b:

let b = 10
var a = 5
a = b
// a тепер дорівнює 10

Якщо права сторона присвоєння є кортежем з кількома значеннями, його елементи
розкладаються у кілька констант чи змінних одночасно:

let (x, y) = (1, 2)
// x тепер дорівнює 1, а y тепер дорівнює 2

На відміну від оператора присвоєння у мовах C та Objective-C, оператор присвоєння у мові Swift сам по собі не повертає значення. Наступні інструкції некоректні:

if x = y {
    // Це не коректно, бо x = y не повертає значення.
}

Ця особливість унеможливлює випадкове використання оператору присвоєння (=) у випадках, коли мається на увазі оператор порівняння (==). Роблячи if x = y некоректним, мова Swift допомагає уникати помилок такого роду у коді.

Арифметичні оператори

Мова Swift підтримує чотири стандартні арифметичні оператори для всіх числових типів:

  • Додавання (+)
  • Віднімання (-)
  • Множення (*)
  • Ділення (/)
1 + 2       // дорівнює 3
5 - 3       // дорівнює 2
2 * 3       // дорівнює 6
10.0 / 2.5  // дорівнює 4.0

На відміну від арифметичних операторів у мовах C та Objective-C, арифметичні оператори мови Swift не дозволяють переповнення змінних за замовчуванням. Можна увімкнути переповнення за допомогою операторів переповнення мови Swift (як, наприклад, a &+ b). Детальніше з ними можна ознайомитись у розділі Оператори переповнення.

Оператор додавання також підтримується для конкатенації рядків (String):

"hello, " + "world"  // дорівнює "hello, world"

Оператор остачі

Оператор остачі (a % b) обчислює, скільки разів b поміститься в a і повертає значення, що залишиться (відоме також як остача).

Примітка

Оператор остачі (%) також відомий як оператор модулю у інших мовах. Однак його поведінка у мові Swift для від’ємних значень значить більше відповідає саме оператору остачі, а не оператору модуля, якщо говорити строго.

Ось як працює оператор остачі. Щоб обчислити 9 % 4, слід спочатку обчислити скільки разів 4 вміститься всередині 9:

Всередині 9 можна вмістити 4 два рази, а залишок буде 1 (показано оранжевим).

У мові Swift, це можна описати як:

9 % 4    // дорівнює 1

Щоб визначити відповідь для a % b, оператор % розв’язує наступне рівняння і повертає остачу як вихідне значення:

a = (b x якийсь множник) + остача

де якийсь множник - це найбільше число, що помножене на bне перевищує a.

Підставивши 9 та 4 у дане рівняння, отримаємо:

9 = (4 x 2) + 1

Точно такий же метод застосовується для обчислення остачі для від’ємного значення a:

-9 % 4   // дорівнює -1

Підставивши -9 та 4 у рівняння, отримаємо:

-9 = (4 x -2) + -1

звідки значення остачі дорівнює -1.

Знак числа b ігнорується для від’ємних значень b. Тобто a % b та a % -b завжди дають одну і ту ж відповідь.

Унарний мінус

Знак числового значення можна змінити за допомогою префіксу -, відомого як оператор унарного мінуса.

let three = 3
let minusThree = -three       // minusThree дорівнює -3
let plusThree = -minusThree   // plusThree дорівнює 3, або "мінус мінус три"

Оператор унарного мінуса (-) додається прямо перед значенням, до якого він застосовується, без жодних пробілів.

Унарний плюс

Оператор унарного плюсу (+) просто повертає значення, до якого він застосовується, без жодних змін:

let minusSix = -6
let alsoMinusSix = +minusSix  // alsoMinusSix дорівнює -6

Хоча унарний плюс фактично нічого не змінює, його доречно вживати, щоб надати симетрії коду для додатних чисел, коли поруч вживається унарний мінус для від’ємних чисел.

Складені оператори присвоєння

Як і в мові C, у мові Swift є складені оператори присвоєння, що поєднують присвоєння (=) з іншою операцією. Одним із прикладів таких операторів є оператор додавання з присвоєнням (+=):

var a = 1
a += 2
// a тепер дорівнює 3

Вираз a += 2 є скороченим записом a = a + 2. Фактично, додавання і присвоєння поєднано в один оператор, що виконує обидві задачі одночасно.

Примітка

Складені оператори присвоєння не повертають значення. Наприклад, не можна написати let b = a += 2. Повний список складених операторів присвоєння стандартної бібліотеки Swift можна знайти у Standard Library Operators Reference

Оператори порівняння

Мова Swift підтримує всі стандартні оператори порівняння мови C:

  • Дорівнює (a == b)
  • Не дорівнює (a != b)
  • Більше (a > b)
  • Менше (a < b)
  • Більше або дорівнює (a >= b)
  • Менше або дорівнює (a <= b)

Примітка

Мова Swift також підтримує два оператори тотожності (=== та !==), котрий слід вживати, що перевірити, що два об’єктних посилання посилаються на один і той же об’єкт. Детальніше це описано у розділі Класи та структури.

Кожен оператор порівняння повертає значення типу Bool щоб вказати, чи істинний вираз:

1 == 1   // true, істина, бо 1 дорівнює 1
2 != 1   // true, істина, бо 2 не дорівнює 1
2 > 1    // true, істина, бо 2 більше ніж 1
1 < 2    // true, істина, бо 1 менше ніж 2
1 >= 1   // true, істина, бо 1 більше або дорівнює 1
2 <= 1   // false, хиба, бо 2 не менше або дорівнює 1

Оператори порівняння часто використовуються в умовних інструкціях, таких як інструкція if:

let name = "world"
if name == "world" {
    print("hello, world")
} else {
    print("I'm sorry \(name), but I don't recognize you")
}
// Друкує "hello, world", бо name звісно дорівнює "world".

Детальніше з інструкцією if можна ознайомитись у розділі Потік керування.

Можна також порівнювати кортежі, що мають однакову кількість значень, якщо кожну пару значень можна порівняти. Наприклад, значення типу Int можуть порівнюватись, і значення типу String теж можуть порівнюватись, а тому і кортежі типу (Int, String) можуть порівнюватись. На відміну від них, значення типу Bool не можна порівнювати (тобто true < false не має сенсу), тому не можна порівнювати кортежі, що містять значення типу Bool.

Кортежі порівнюються зліва направо, по одній парі значень за раз, допоки не зустрінеться пара значень, що не дорівнюють одне одному. Ці два значення порівнюються, і результат цього порівняння визначає весь результат порівняння кортежів. Якщо всі елементи рівні, тоді й кортежі у свою чергу теж рівні. Наприклад:

(1, "zebra") < (2, "apple")   // істина, бо 1 менше ніж 2; "zebra" та "apple" не порівнюються
(3, "apple") < (3, "bird")    // істина, бо 3 дорівнює 3, а "apple" менше ніж "bird"
(4, "dog") == (4, "dog")      // істина, бо 4 дорівнює 4, а "dog" дорівнює "dog"

У прикладі вище, можна бачити як працює порівняння зліва направо у першому рядку. Оскільки 1 менше ніж 2, кортеж (1, "zebra") вважається меншим, ніж (2, "apple"), незалежно від інших значень у кортежі. Не має значення, що "zebra" не менше ніж "apple", тому що результат порівняння кортежів вже визначено по парі перших елементів кортежів. Однак, коли перші елементи кортежів дорівнюють одне одному, друга пара елементів порівнюється — що й відбувається у другому і третьому рядках.

Примітка

Стандартна бібліотека мови Swift включає оператори порівняння кортежів із кількістю елементів до семи. Щоб порівнювати кортежі із сімома чи більше елементами, слід самому реалізувати оператори порівняння для них.

Тернарний умовний оператор

Тернарний умовний оператор є особливим оператором із трьома частинами, що має форму питання ? відповідь1 : відповідь2. Це скорочення від виконання одного із двох виразів в залежності від того, чи питання є true або false. Якщо питання є true, буде виконано відповідь1 і повернуто відповідне значення; в іншому випадку, буде виконано відповідь2 і повернуто її значення.

Тернарний умовний оператор є скороченим записом наступного коду:

if питання {
    відповідь1
} else {
    відповідь2
}

Ось приклад, де підраховується висота рядку в таблиці. Висота рядку має бути на 50 точок вище ніж висота контенту, якщо у рядку є заголовок, і на 20 точок вище, якщо рядок не має заголовку:

let contentHeight = 40                // висота контенту
let hasHeader = true                // чи має рядок заголовок
let rowHeight = contentHeight + (hasHeader ? 50 : 20)
// rowHeight дорівнює 90

Попередній приклад є скороченням від наступного коду:

let contentHeight = 40
let hasHeader = true
let rowHeight: Int
if hasHeader {
    rowHeight = contentHeight + 50
} else {
    rowHeight = contentHeight + 20
}
// rowHeight дорівнює 90

Використання тернарного умовного оператора в першому прикладі дає можливість задати правильне значення rowHeight одним рядком коду, що більше лаконічно, ніж код у другому прикладі.

Тернарний умовний оператор надає ефективне скорочення, щоб вибрати, який із виразів обчислювати. Однак тернарних умовний оператор слід вживати обережно. При надмірному вживанні його стислість може призвести до коду, який важко читати. Слід уникати поєднання кількох тернарних умовних операторів у одну складену інструкцію.

Оператор поглинання nil

Оператор поглинання nil (a ?? b) розгортає опціонал a якщо він містить значення, або повертає значення за замовчуванням b, якщо a є nil. Вираз a завжди має опціональний тип. Вираз b має мати тип, що збігається з типом, що зберігається всередині a.

Оператор поглинання nil є скороченням наступного коду:

a != nil ? a! : b

Код вище використовує тернарний умовний оператор і примусове розгортання (a!)
щоб отримати значення, загорнуте всередині коли a не nil, і повернути b в іншому випадку. Оператор поглинання nil надає більш елегантний спосіб інкапсулювати цю умовну перевірку та розгортання у лаконічну і легку для читання форму.

Примітка

Якщо значення a не nil, значення b не обчислюється. Це відомо як обчислення за коротким обходом.

У прикладі нижче оператор поглинання nil використовується для того, щоб вибрати між назвою кольору за замовчанням і назвою кольору, опціонально заданою користувачем:

let defaultColorName = "red"
var userDefinedColorName: String?   // nil за замовчуванням

var colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName дорівнює nil, тому colorNameToUse присвоєно колір за замовчуванням "red"

Змінну userDefinedColorName визначено як опціональний String, зі значенням nil за замовчуванням. Оскільки змінна userDefinedColorName має опціональний тип, до неї можна застосувати оператор поглинання nil. У прикладі вище цей оператор вживається, щоб визначити початкове значення змінної colorNameToUse типу String. Оскільки userDefinedColorName містить nil, вираз userDefinedColorName ?? defaultColorName повертає значення defaultColorName, або "red".

Якщо присвоїти певне значення, що не є nil, змінній userDefinedColorName, і провести операцію поглинання nil знову, значення загорнуте в опціонал userDefinedColorName буде використано замість значення за замовчуванням:

userDefinedColorName = "green"
colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName не дорівнює nil, тому colorNameToUse присвоєно значення "green"

Оператори діапазонів

Мова Swift включає два оператори діапазонів, котрі скорочують вираження діапазону значень.

Оператор закритого діапазону

Оператор закритого діапазону (a...b) визначає діапазон від a до b, і включає значення a та b. Значення a має бути не більшим за значення b. Оператор закритого діапазону зручно вживати для ітерування діапазону, в якому бажано пройтись по всім значенням, як то, наприклад, у циклі for-in:

for index in 1...5 {
    print("\(index) помножити на 5 дорівнює \(index * 5)")
}
// 1 помножити на 5 дорівнює 5
// 2 помножити на 5 дорівнює 10
// 3 помножити на 5 дорівнює 15
// 4 помножити на 5 дорівнює 20
// 5 помножити на 5 дорівнює 25

Детальніше з циклом for-in можна ознайомитись у розділі Потік керування.

Оператор напіввідкритого діапазону

Оператор напіввідкритого діапазону (a..<b) визначає діапазон від a до b, котрий включає a, але не включає b. Його називають напіввідкритим, бо він включає перше значення, але не включає останнє. Як і з оператором закритого діапазону, значення a не може бути більшим за значення b. Якщо значення a дорівнює значенню b, тоді результатом буде порожній діапазон.

Напіввідкриті діапазони зокрема зручно вживати під час роботи зі списками, проіндексованими починаючи з нуля, наприклад, із масивами, де зручно рахувати до довжини списку (але не включно):

let names = ["Ганна", "Олекса", "Борис", "Жорж"]
let count = names.count
for i in 0..<count {
    print("Особу \(i + 1) звати \(names[i])")
}
// Особу 1 звати Ганна
// Особу 2 звати Олекса
// Особу 3 звати Борис
// Особу 4 звати Жорж

Слід помітити, що масив містить чотири елементи, але діапазон 0..<count дораховує лише до 3 (індекс останнього елемента в масиві), бо цей діапазон - напіввідкритий. Детальніше з масивами можна ознайомитись у розділі Масиви.

Логічні оператори

Логічні оператори змінюють чи поєднують Булеві значення true та false. Мова Swift підтримує три основні логічні оператори, що можна зустріти у C-подібних мовах:

  • Логічне НЕ (!a)
  • Логічне І (a && b)
  • Логічне АБО (a || b)

Оператор логічного НЕ

Оператор логічного НЕ (!a) інвертує Булеве значення, так що true стає false, а false стає true.

Оператор логічного НЕ є префіксним оператором, і ставиться прямо перед значенням, над яким він оперує, без жодних пробілів. Його можна прочитати як “не a”, як видно в наступному прикладі:

let allowedEntry = false    // дозволено ввійти
if !allowedEntry {           // не дозволено ввійти
    print("ВХІД ЗАБОРОНЕНО")
}
// Надрукує "ВХІД ЗАБОРОНЕНО"

Фраза if !allowedEntry читається “if not allowed entry.”, тобто “якщо не дозволено ввійти.” Наступний рядок виконується тільки якщо “не дозволено ввійти” дорівнює true; тобто, якщо allowedEntry дорівнює false.

Як видно у цьому прикладі, акуратний вибір імен Булевих констант та змінних допомагає робити код виразним та зручним до читання, уникаючи подвійного заперечення та логічних конструкцій, що збивають з пантелику.

Оператор логічного І

Оператор логічного І (a && b) створює логічний вираз, де обидва значення мають бути істинними (true), щоб увесь вираз був істинним (true).

Якщо хоча б одне зі значень хибне (false), увесь вираз теж буде хибним (false). Фактично, якщо перше значення є хибне (false), друге значення навіть не буде обчислене, бо воно вже не зможе зробити весь вираз істинним (true). Це відомо як обчислення за коротким обходом.

Наступний приклад розглядає два значення типу Bool і дозволяє ввійти тільки тоді, коди обидва з них істинні (true):

let enteredDoorCode = true            // введено дверний код
let passedRetinaScan = false        // пройдено сканування сітківки
if enteredDoorCode && passedRetinaScan {
    print("Вітаємо!")
} else {
    print("ВХІД ЗАБОРОНЕНО")
}
// Надрукує "ВХІД ЗАБОРОНЕНО"

Оператор логічного АБО

Оператор логічного АБО (a || b) є інфіксний оператор, що пишеться як два символи труби підряд. Його вживають щоб створити логічний вираз, у якому хоча б одне із двох значень має бути істинним (true), щоб увесь вираз був істинним (true).

Як і оператор логічного І вище, оператор логічного АБО виконує обчислення за коротким обходом. Якщо ліва частина оператора логічного АБО обчислюється як істинна (true), то права частина не обчислюється, бо вона не може змінити вихід всього виразу.

У прикладі нижче, перше булеве значення (hasDoorKey) дорівнює false, але друге значення (knowsOverridePassword) дорівнює true. Оскільки одне зі значень дорівнює true, увесь вираз обчислюється як true, і вхід дозволяється:

let hasDoorKey = false                    // має дверний ключ
let knowsOverridePassword = true        // знає аварійний пароль
if hasDoorKey || knowsOverridePassword {
    print("Вітаємо!")
} else {
    print("ВХІД ЗАБОРОНЕНО")
}
// Надрукує "Вітаємо!"

Поєднання логічних операторів

Можна об’єднувати кілька логічних операторів, щоб створити довші складені вирази:

if enteredDoorCode && passedRetinaScan || hasDoorKey || knowsOverridePassword {
    print("Вітаємо!")
} else {
    print("ВХІД ЗАБОРОНЕНО")
}
// Надрукує "Вітаємо!"

У цьому прикладі кілька операторів && та || використовуються для створення довшого складеного виразу. Однак, оператори && та || все ж оперують тільки над двома значеннями, тож фактично це є три менші вирази поєднані разом у ланцюжок. Даний приклад можна прочитати так:

Якщо введено правильний код дверей і пройдено сканування сітківки, або якщо ми маємо потрібний ключ від дверей, або якщо ми знаємо аварійний пароль, тоді вхід слід дозволити.

На основі значень enteredDoorCode, passedRetinaScan, та hasDoorKey, перші два підвирази обчислюються як false. Однак, аварійний пароль відомо (knowsOverridePassword дорівнює true), тому увесь складений вираз обчислюється як true.

Примітка

Логічні оператори && та || в мові Swift мають ліву асоціативність, тобто складені оператори з кількома логічними операторами обчислюють спершку найбільш лівий підвираз.

Явні дужки

Іноді корисно включити круглі дужки, де вони не є строго необхідні, щоб зробити зручним для читання намір, з яким було створено складений вираз. У наведеному вище прикладі із доступом до дверей, було б корисно додати круглі дужки довкола першої частини складеного виразу, щоб зробити його намір явним:

if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword {
    print("Вітаємо!")
} else {
    print("ВХІД ЗАБОРОНЕНО")
}
// Надрукує "Вітаємо!"

Круглі дужки явно вказують на те, що перші два булеві значення розуміються як частина окремого можливого стану у загальній логіці. Значення складеного виразу не змінюється, але тепер читачу стає зрозумілішим намір, з яким його було створено. Зрозумілість завжди важливіша за лаконічність; слід вживати круглі дужки усюди, де вони допомагають зрозуміти ваш намір.