Link Search Menu Expand Document

Функції

Функція - це самодостатній шматок коду, що виконує конкретну задачу. Функціям дають імена, що вказують на призначення функції, і ці імена використовуються для “виклику” функції для виконання її задачі, коли це потрібно.

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

Кожна функція у Swift має тип, що складається із типів параметрів функції та типу, що повертається. Ці типи можна використовувати як і будь-які інші типи у Swift, що полегшує передачу функцій у якості параметрів до інших функцій, та повернення функції з іншої функції. Функції також можна записувати всередині інших функцій, щоб інкапсулювати корисну функціональність всередині контексту певної функції.

Оголошення та виклик функцій

Під час оголошення функції, можна (але необов’язково) оголосити одне чи більше іменоване й типізоване значення, котре функція прийматиме на вхід, яке називається параметром функції. Також можна (але необов’язково) оголосити тип значення, що буде повертатись із функції після її виконання. Цей тип ми будемо називати тип, що повертається.

Кожна функція має ім’я функції, котре описує задачу, що виконує функція. Щоб скористатись функцією, слід “викликати” функцію за допомогою її імені, та передавши їй вхідні значення (відомі як аргументи), що співпадають за типами із параметрами функції. Аргументи функції повинні завжди йти у тому ж порядку, що й список параметрів функції.

У наступному прикладі функція має ім’я greet(person:) (дослівно, привітати(особу:)), бо це власне те, що вона робить: приймає ім’я особи на вхід та повертає привітання для цієї особи. Щоб досягнути цього, оголошується один вхідний параметр – значення типу String, що називається person – та тип, що повертається, String, котрий буде містити привітання для даної особи.

func greet(person: String) -> String {
    let greeting = "Вітаємо вас, " + person + "!"
    return greeting
}

Всю цю інформацію згорнуто в оголошення функції, котре починається із ключового слова func. Назва типу, що повертає функція, записується після стрілки повернення -> (дефіс та права кутова дужка).

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

print(greet(person: "Муся"))
// Надрукує "Вітаємо вас, Муся!"
print(greet(person: "Гриша"))
// Надрукує "Вітаємо вас, Гриша!"

Функція greet(person:) викликається з передачею в неї значення типу String, що вказується після мітки аргументу person, наприклад greet(person: "Муся"). Оскільки дана функція повертає значення типу String, виклик цієї функції можна обгорнути у виклик функції print(_:separator:terminator:), щоб одразу надрукувати та переглянути значення, котре поверне greet(person:).

Примітка

Функція print(_:separator:terminator:) не має мітки для свого першого аргумента, а решта її аргументів необов’язкові, бо мають значення за замовчанням. Ці варіації синтаксису функцій описані нижче у підрозділах Мітки аргументів функцій та імена їх параметрів та Значення параметрів за замовчуванням.

Тіло функції greet(person:) починається з оголошення нової константи типу String на ім’я greeting та присвоєння їй простого вітального повідомлення. Це повідомлення передається назад із функції за допомогою ключового слова return. У рядку коду return greeting, функція завершує своє виконання та передає поточне значення константи greeting.

Функцію greet(person:) можна викликати багато разів із різними вхідними значеннями. У прикладі вище показано, що відбувається, коли цю функцію викликають із вхідним значенням "Муся", та із вхідним значенням "Гриша". Функція повертає зшите привітання у кожному з випадків.

Щоб зробити тіло цієї функції коротшим, можна об’єднати створення повідомлення та інструкцію повернення return в одному рядку:

func greetAgain(person: String) -> String {
    return "Знову вітаємо вас, " + person + "!"
}
print(greetAgain(person: "Муся"))
// Надрукує "Знову вітаємо вас, Муся!"

Параметри функцій та значення, які вони повертають

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

Функції без параметрів

Функції не обов’язково повинні мати вхідні параметри. Ось приклад функції без вхідних параметрів, котра повертає завжди один і той же рядок при виклику:

func sayHelloWorld() -> String {
    return "привіт, світ"
}
print(sayHelloWorld())
// Надрукує "привіт, світ"

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

Функції із кількома параметрами

Функції можуть мати декілька вхідних параметрів, котрі записуються всередині дужок і розділяються комами.

Наступна функція приймає на вхід ім’я особи та булеве значення, яке вказує, чи привітали вже цю особу; функція найбільш доречне привітання для цієї особи:

func greet(person: String, alreadyGreeted: Bool) -> String {
    if alreadyGreeted {
        return greetAgain(person: person)
    } else {
        return greet(person: person)
    }
}
print(greet(person: "Сергій", alreadyGreeted: true))
// Надрукує "Знову вітаємо вас, Сергій!"

При виклику функції greet(person:alreadyGreeted:) до неї передаються аргумент типу String з міткою person, та аргумент типу Bool з міткою alreadyGreeted, при цьому ці аргументи записуються в дужках та розділяються комою. Слід помітити, що дана функція не співпадає із функцією greet(person:) з попереднього підрозділу. Хоч обидві функції і мають імена, що починаються із greet, функція greet(person:alreadyGreeted:) приймає два аргументи, тоді як функція greet(person:) приймає лише один аргумент.

Функції, що не повертають значення

Функції не обов’язково повинні повертати значення. Ось приклад функції greet(person:), котра друкує рядок із привітанням замість того, щоб повертати його:

func greet(person: String) {
    print("Вітаємо вас, \(person)!")
}
greet(person: "Людмила")
// Надрукує "Вітаємо вас, Людмила!"

Оскільки функція не повертає жодного значення, в оголошенні функції пропущено стрілку повертання та тип, що повертається.

Примітка

Строго кажучи, дана версія функції greet(person:) повертає значення, хоч воно і не визначене явно. Функції, що не оголошують тип, що повертається, мають особливий тип, що повертається: Void. Цей тип у Swift є просто порожнім кортежем, що записується як ().

Значення, що повертається функцією, можна проігнорувати при її виклику:

func printAndCount(string: String) -> Int {
    print(string)
    return string.characters.count
}
func printWithoutCounting(string: String) {
    let _ = printAndCount(string: string)
}
printAndCount(string: "привіт, світ")
// Надрукує "привіт, світ" та поверне значення 12
printWithoutCounting(string: "привіт, світ")
// Надрукує "привіт, світ" та не поверне жодного значення

Перша функція, printAndCount(string:), надрукує рядок, і потім поверне кількість символів у ньому у вигляді числа типу Int. Друга функція, printWithoutCounting(string:), викличе першу функцію, але проігнорує значення, котре поверне перша функція. Коли викликається друга функція, першою функцією буде надруковано повідомлення, проте повернуте нею значення не буде використано.

Примітка

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

Функції, що повертають кілька значень

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

Наступний приклад демонструє оголошення функції на ім’я minMax(array:), котра знаходить найменше та найбільше число в масиві цілочисельних значень типу Int:

func minMax(array: [Int]) -> (min: Int, max: Int) {
    var currentMin = array[0]
    var currentMax = array[0]
    for value in array[1..<array.count] {
        if value < currentMin {
            currentMin = value
        } else if value > currentMax {
            currentMax = value
        }
    }
    return (currentMin, currentMax)
}

Функція minMax(array:) повертає кортеж, що містить два цілих значення Int. Ці значення іменуються min та max, тому їх можна дістати з кортежу, що повертає дана функція, за допомогою цих імен.

Тіло функції minMax(array:) починає роботу із присвоєння двом робочим змінним currentMin та currentMax значення першого елементу в масиві. Далі функція ітерує решту значень у масиві, та перевіряє кожне значення, чи воно менше за currentMin або більше за currentMax. Таким чином обчислюються загальні мінімум та максимум даного масиву, які повертаються як кортеж значень Int.

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

let bounds = minMax(array: [8, -6, 2, 109, 3, 71])
print("min = \(bounds.min); max = \(bounds.max)")
// Надрукує "min = -6; max = 109"

Слід зазначити, що елементи кортежу не обов’язково іменувати в момент повернення із функції, бо їх імена вже вказано в оголошенні типу, що повертає дана функція.

Опціональні кортежі у якості значень, що повертають функції

Нехай ми маємо функцію, що повертає кортеж. Якщо існує ймовірність, що ця функція може не повернути жодного значення, слід використовувати опціональний кортеж як тип значення, що повертається, і таким чином відобразити факт, що весь кортеж може мати значення nil. Щоб записати опціональний кортеж як значення, що повертає функція, слід додати знак питання після дужки, що закриває кортеж. Наприклад: (Int, Int)? або (String, Int, Bool)?.

Примітка

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

Функція minMax(array:) з прикладу вище повертає кортеж із двох значень Int. Однак, дана функція не робить жодних перевірок безпеки на масиві, що їй передається. Якщо аргумент array буде містити порожній масив, функція minMax(array:) в оголошенні вище спровокує помилку часу виконання при спробі доступу до array[0].

Щоб обробити ситуацію з порожнім масивом, напишемо нову функцію minMax(array:), котра буде повертати опціональний кортеж, або nil, коли масив є порожнім:

func minMax(array: [Int]) -> (min: Int, max: Int)? {
    if array.isEmpty { return nil }
    var currentMin = array[0]
    var currentMax = array[0]
    for value in array[1..<array.count] {
        if value < currentMin {
            currentMin = value
        } else if value > currentMax {
            currentMax = value
        }
    }
    return (currentMin, currentMax)
}

Для перевірки, чи повернула функція minMax(array:) власне значення чи nil, можна використати прив’язування опціоналів:

if let bounds = minMax(array: [8, -6, 2, 109, 3, 71]) {
    print("min = \(bounds.min); max = \(bounds.max)")
}
// Надрукує "min = -6; max = 109"

Функції з неявним поверненням

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

func greeting(for person: String) -> String {
    "Вітаю, " + person + "!"
}
print(greeting(for: "Дмитро"))
// Надрукує "Вітаю, Дмитро!"

func anotherGreeting(for person: String) -> String {
    return "Вітаю, " + person + "!"
}
print(anotherGreeting(for: "Дмитро"))
// Надрукує "Вітаю, Дмитро!"

Все визначення функції greeting(for:) є привітальним повідомленням, яке вона повертає, а тому ця функція може послуговуватись цією скороченою формою запису. Функція anotherGreeting(for:) повертає те ж саме привітальне повідомлення, використовуючи ключове слово return як довша функція. У кожній функції, котру можна записати як єдиний рядок з інструкцією return, можна пропускати ключове слово return.

Як буде видно у розділі Скорочене оголошення гетерів, у гетерах властивостей також можна послуговуватись неявним поверненням.

Примітка

Код, котрий ви пишете у якості значення, котре повертається неявно, повинен повертати якесь значення. Наприклад, не можна вказати print(13) як значення, що повертається неявно. Однак, можна використовувати функції, з яких ніколи не відбувається повернення, на кшталт fatalError("Oh no!"), як значення, що повертається неявно: Swift розуміє, що неявне повернення не стається.

Мітки аргументів функцій та імена їх параметрів

Кожен параметр функції має як мітку аргументу, так і ім’я параметра. Мітка аргументу використовується при виклику функції; кожен аргумент у виклику функції записується після мітки аргументу. Ім’я параметра використовується в реалізації функції. За замовчанням, імена параметрів використовуються як мітки аргументів.

func someFunction(firstParameterName: Int, secondParameterName: Int) {
    // В тілі функції, імена firstParameterName та secondParameterName
    // відносяться до значень аргументів для першого і другого параметрів
}
someFunction(firstParameterName: 1, secondParameterName: 2)

Імена параметрів функції мають бути неповторними. Мітки аргументів кількох параметрів можуть співпадати, однак заради полегшення читання коду, варто робити їх різними.

Вказування міток аргументів

Щоб вказати мітку аргументу, слід прописати її перед іменем параметра, розділивши їх пробілом:

func someFunction(argumentLabel parameterName: Int) {
    // У тілі функції, parameterName вказує на значення аргумента для цього параметра.
}

Ось варіація функції greet(person:), що приймає на вхід назву рідного міста особи, і повертає привітання:

func greet(person: String, from hometown: String) -> String {
    return "Вітаємо вас, \(person)! Раді, що ви завітали до нас із міста \(hometown)."
}
print(greet(person: "Віра", from: "Славутич"))
// Надрукує "Вітаємо вас, Віра! Раді, що ви завітали до нас із міста Славутич."

Використання міток аргументів дозволяє виклику функції читатись виразно, неначе речення, при цьому тіло функції залишається виразним, зі зрозумілим наміром. Виклик функції читається дослівно привітати(особу: "Віра", із: "Славутича").

Пропуск міток аргументів

Якщо потрібно оголосити параметр без мітки аргументу, слід писати символ підкреслення (_) замість явного вказування мітки аргументу для цього параметра.

func someFunction(_ firstParameterName: Int, secondParameterName: Int) {
    // В тілі функції, firstParameterName та secondParameterName 
    // вказують на значення аргументів для першого і другого параментів.
}
someFunction(1, secondParameterName: 2)

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

Значення параметрів за замовчуванням

Можна визначати значення за замовчанням для будь-якого параметра функції, шляхом присвоєння значення цьому параметру після вказування типу параметра. Якщо визначено значення параметра за замовчанням, цей параметр можна не вказувати при виклику функції.

func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) {
    // Якщо пропустити другий аргументи при виклику функції, 
    // значення parameterWithDefault буде дорівнювати 12 всередині тіла функції.
}
someFunction(parameterWithoutDefault: 3, parameterWithDefault: 6) // parameterWithDefault дорівнює 6
someFunction(parameterWithoutDefault: 4) // parameterWithDefault дорівнює 12

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

Варіативні функції

Функції зі змінною кількістю аргументів називають варіативними функціями. Передача змінної кількості параметрів до таких функцій відбувається за допомогою варіативного параметра, що об’єднує в собі нуль або декілька значень одного типу. Варіативний параметр записується шляхом вказування трьох крапок (...) після назви типу параметра.

Значення, що передаються до функції за допомогою варіативного параметра, є доступними в тілі функцій як масив відповідного типу. Наприклад, варіативний параметр на ім’я numbers з типом Double... в тілі функції буде виглядати як константа numbers типу [Double].

У наступному прикладі обчислюється середнє арифметичне (також відоме як просто середнє) для списку чисел довільної довжини:

func arithmeticMean(_ numbers: Double...) -> Double {
    var total: Double = 0
    for number in numbers {
        total += number
    }
    return total / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5)
// поверне 3.0, що є середнім арифментичним цих п'яти чисел
arithmeticMean(3, 8.25, 18.75)
// поверне 10.0, що є середнім арифментичним цих трьох чисел

Функції можуть мати декілька варіативних параметрів. Перший параметр, що йде після іншого варіативного параметра, повинен мати мітку аргументу. Мітка аргументу робить однозначним те, які аргументи передаються до кожного з варіативних параметрів.

Двонаправлені параметри

За замовчанням, параметри функцій є константами. Спроба змінити значення параметра функції всередині її тіла призводить по помилки часу компіляції. Це запобігає помилковій зміні значення параметра. Якщо ж дійсно потрібно змінити значення параметра, і щоб ці зміни збереглись після завершення виклику функції, слід оголосити параметр двонаправленим.

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

Як аргумент двонаправленого параметра можна використовувати лише змінні. Не можна передати константу чи значення літералу як аргумент, по константи та літерали не можна змінювати. Перед назвою змінної, що передається у функцію як двонаправлений параметр, потрібно ставити амперсанд (&), щоб позначити, що значення даної змінної може бути змінене функцією.

Примітка

Двонаправлені параметри не можуть мати значення за замовчанням, чи бути варіативними.

Ось приклад функції swapTwoInts(_:_:), котра містить два двонаправлені параметри, a і b:

func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}

Функція swapTwoInts(_:_:) просто міняє місцями значення a і b: значення змінної a присвоюється змінній b, водночас значення змінної b присвоюється змінній a. Функція виконує цей обмін шляхом зберігання значення a у тимчасовій константі на ім’я temporaryA, присвоюючи значення b змінній a, після цього присвоюючи значення temporaryA змінній b.

Тепер можна викликати функцію swapTwoInts(_:_:) з двома змінними типу Int для обміну їх значеннями. Слід помітити, що у наступному прикладі, перед назвами змінних someInt та anotherInt у виклику функції swapTwoInts(_:_:) стоять амперсанди:

var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt тепер дорівнює \(someInt), а anotherInt тепер дорівнює \(anotherInt)")
// Надрукує "someInt тепер дорівнює 107, а anotherInt тепер дорівнює 3"

Приклад вище демонструє, що початкові значення змінних someInt та anotherInt було змінено функцією swapTwoInts(_:_:), хоч початково ці змінні було оголошено за межами функції.

Примітка

Двонаправлені переметри не є тим же самим, що повертання значення з функції. У прикладі вище, функція swapTwoInts не оголошує типу значення, що повертається, і не повертає жодного значення, але тим не менше змінює значення someInt та anotherInt. Двонаправлені параметри є альтернативним способом для функції щось змінити поза межами контексту свого тіла.

Функції як типи

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

Наприклад:

func addTwoInts(_ a: Int, _ b: Int) -> Int {
    return a + b
}

func multiplyTwoInts(_ a: Int, _ b: Int) -> Int {
    return a * b
}

У даному прикладі оголошуються дві прості математичні функції, що називаються addTwoInts та multiplyTwoInts. Кожна з цих функцій приймає на вхід два значення типу Int, і повертає значення типу Int, котре містить результат виконання математичної операції.

Типом обох цих функцій є (Int, Int) -> Int. Це може читатись як:

“Функція, що має два параметру, обидва типу Int, і котра повертає значення типу Int.”

Ось іще один приклад, де функція не має параметрів і не повертає нічого:

func printHelloWorld() {
    print("привіт, світ!")
}

Типом даної функції є () -> Void, тобто “функція, що не має параметрів та повертає Void.”

Використання функціональних типів

У Swift, функції можна використовувати як будь-які інші типи. Наприклад, можна оголосити константу чи змінну з функціональним типом, і присвоїти їй функцію відповідного типу як значення:

var mathFunction: (Int, Int) -> Int = addTwoInts

Це можна прочитати, як:

“Оголошуємо змінну на ім’я mathFunction, котра має тип ‘функція, що приймає два аргументи типу Int, та повертає значення типу Int.’ Цій новій змінній присвоюємо посилання на функцію на ім’я addTwoInts.”

Функція addTwoInts(_:_:) має той же само тип що і змінна mathFunction, тому це присвоєння дозволяється перевіркою типів Swift.

Тепер можна викликати присвоєну функцію за допомогою змінної mathFunction:

print("Результат: \(mathFunction(2, 3))")
// Надрукує "Результат: 5"

Цій же змінній можна присвоїти іншу функцію такого ж типу, так само як присвоюються нефункціональні типи.

mathFunction = multiplyTwoInts
print("Результат: \(mathFunction(2, 3))")
// Надрукує "Результат: 6"

Як і з іншими типами, можна дозволити виведенню типів Swift визначити функціональний тип при присвоєнні функції константі чи змінній:

let anotherMathFunction = addTwoInts
// тип anotherMathFunction визначено як (Int, Int) -> Int

Функціональні типи як типи параметрів

Можна використовувати функціональні типи, такі як (Int, Int) -> Int, як типи параметрів для інших функцій. Це дозволяє залишати певні аспекти реалізації функції тому, хто викличе функцію і надасть функціональний параметр при виклику.

Ось приклад функції, що друкує результат математичної функції з прикладів вище:

func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
    print("Результат: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)
// Надрукує "Результат: 8"

У даному прикладі оголошено функцію з іменем printMathResult(_:_:_:), котра має три параметри. Перший параметр називається mathFunction, і має тип (Int, Int) -> Int. Можна передати будь-яку функцію даного типу як аргумент для цього параметра. Другий та третій параметри називаються a та b, і обидва мають тип Int. Ці параметри використовуються як вхідні значення для функції, що передається як перший аргумент.

Коли викликається функція printMathResult(_:_:_:), їх передається функція addTwoInts(_:_:) та два цілих значення 3 та 5. Передана функція викликається із вхідними значеннями 3 and 5, і результат – 8 – друкується.

Роль функції printMathResult(_:_:_:) – надрукувати результат виклику математичної функції відповідного типу. Немає різниці, що саме робить реалізація математичної функції – головне, щоб ця функція мала відповідний тип. Це дозволяє функції printMathResult(_:_:_:) передати типобезпечним способом частину своєї функціональності тому, хто її викличе.

Функціональні типи як типи, що повертаються

Функціональний тип можна використовувати як тип, що повертається іншою функцією. Для цього повний функціональний тип записується після стрілки повернення (->) функції, що повертає цей тип.

У наступному прикладі визначено дві прості функції, що називаються stepForward(_:) та stepBackward(_:). Функція stepForward(_:) повертає значення, котре на одиницю більше за вхідне, а функція stepBackward(_:) – значення, котре на одиницю менше за вхідне значення. Обидві функції мають тип (Int) -> Int:

func stepForward(_ input: Int) -> Int {
    return input + 1
}

func stepBackward(_ input: Int) -> Int {
    return input - 1
}

Ось приклад функції, що називається chooseStepFunction(backward:) і повертає тип (Int) -> Int. Функція chooseStepFunction(backward:) повертає функцію stepForward(_:) або функцію stepBackward(_:) в залежності від параметра типу Boolean на ім’я backward:

func chooseStepFunction(backward: Bool) -> (Int) -> Int {
    return backward ? stepBackward : stepForward
}

Тепер можна використовувати функцію chooseStepFunction(backward:), щоб отримати функцію, що збільшувати чи зменшувати значення:

var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero тепер вказує на функцію stepBackward()

У прикладі вище визначається, який крок (вверх чи вниз) потрібно застосовувати до змінної currentValue, щоб наблизити її до нуля. Змінна currentValue має початкове значення 3, тому умова currentValue > 0 обчислиться як true, через що функція chooseStepFunction(backward:) поверне функцію stepBackward(_:). Посилання на цю повернену функцію збережено у константі на ім’я moveNearerToZero.

Тепер, коли константа moveNearerToZero посилається на коректну функцію, вона може використовуватись для зворотнього відліку до нуля:

print("Зворотній відлік до нуля:")
// Зворотній відлік до нуля:
while currentValue != 0 {
    print("\(currentValue)... ")
    currentValue = moveNearerToZero(currentValue)
}
print("Нуль!")
// 3...
// 2...
// 1...
// Нуль!

Вкладені функції

Всі функції, з якими ми мали справу дотепер у цьому розділі, були прикладами глобальних функцій, котрі визначено в глобальній області видимості. Однак, не всі функції повинні бути глобальними. Наприклад, можна створювати вкладені функції, тобто функції, оголошені всередині тіл інших функцій.

Вкладені функції не видно за замовчуванням у зовнішньому контексті, але їх можна викликати за допомогою функції, в якій їх оголошено. Функція, в якій оголошено вкладені функції, може повернути одну із них для використання в іншому контексті.

Функцію chooseStepFunction(backward:) з прикладу вище можна переписати з використанням вкладених функцій:

func chooseStepFunction(backward: Bool) -> (Int) -> Int {
    func stepForward(input: Int) -> Int { return input + 1 }
    func stepBackward(input: Int) -> Int { return input - 1 }
    return backward ? stepBackward : stepForward
}
var currentValue = -4
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero тепер вказує на функцію stepForward()
while currentValue != 0 {
    print("\(currentValue)... ")
    currentValue = moveNearerToZero(currentValue)
}
print("Нуль!")
// -4...
// -3...
// -2...
// -1...
// Нуль!