Видеокурсы по изучению языка программирования Swift. Подробнее

Последующее замыкание

Если вы нашли опечатку в тексте, выделите ее и нажмите CTRL + ENTER.

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

func someFunctionThatTakesAClosure(closure: () -> Void) {
   // тело функции
}
 
// Вот как вы вызываете эту функцию без использования последующего замыкания:
 
someFunctionThatTakesAClosure(closure: {
   // тело замыкания
})
 
// Вот как вы вызываете эту функцию с использованием последующего замыкания:
 
someFunctionThatTakesAClosure() {
   // тело последующего замыкания
}

Сортирующее строки замыкание из раздела Синтаксис замыкающего выражения может быть записано вне круглых скобок функции sorted(by:), как последующее замыкание:

reversedNames = names.sorted() { $0 > $1 }

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

reversedNames = names.sorted { $0 > $1 }

Последующие замыкания полезны в случаях, когда само замыкание достаточно длинное, и его невозможно записать в одну строку. В качестве примера приведем вам метод map(_:) типа Array в языке Swift, который принимает выражение замыкания как его единственный аргумент. Замыкание вызывается по одному разу для каждого элемента массива и возвращает альтернативную отображаемую величину (возможно другого типа) для этого элемента. Природа отображения и тип возвращаемого значения определяется замыканием.

После применения замыкания к каждому элементу массива, метод map(_:) возвращает новый массив, содержащий новые преобразованные величины, в том же порядке, что и в исходном массиве.

Вот как вы можете использовать метод map(_:) вместе с последующим замыканием для превращения массива значений типа Int в массив типа String. Массив [16, 58, 510] используется для создания нового массива ["OneSix", "FiveEight", "FiveOneZero"] :

let digitNames = [
    0: "Zero", 1: "One", 2: "Two",   3: "Three", 4: "Four",
    5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]

Код выше создает словарь отображающий цифры и их английскую версию имен. Так же он объявляет массив целых значений для преобразования в массив строк.

Вы можете использовать массив numbers для создания значений типа String, передав замыкающее выражение в метод map(_:) массива в качестве последующего замыкания. Обратите внимание, что вызов number.map не включает в себя скобки после map, потому что метод map(_:) имеет только один параметр, который мы имеем в виде последующего замыкания:

let strings = numbers.map { (number) -> String in
    var number = number
    var output = ""
    repeat {
        output = digitNames[number % 10]! + output
        number /= 10
    } while number > 0
    return output
}

//тип строк был выведен как [String]
//значения ["OneSix", "FiveEight", "FiveOneZero"]

Метод map(_:) вызывает замыкание один раз для каждого элемента массива. Вам не нужно указывать тип входного параметра замыкания, number, так как тип может быть выведен из значений массива, который применяет метод map.

В этом примере переменная number инициализирована при помощи значения параметра замыкания number, так что значение может быть изменено внутри тела замыкания. (Параметры функций и замыкания всегда являются константами.) Выражение замыкания так же определяет возвращаемый тип String для указания типа, который будет храниться в массиве на выходе из метода map(_:).

Замыкающее выражение строит строку, названную output, каждый раз, когда оно вызывается. Оно рассчитывает последнюю цифру number, используя оператор деления с остатком ( nubmer % 10 ) и использует затем эту получившуюся цифру, чтобы найти соответствующую строку в словаре digitNames. Это замыкание может быть использовано для создания строкового представления любого целого числа, большего чем 0.

Заметка

Вызов словаря digitNames синтаксисом сабскрипта сопровождается знаком (!), потому что сабскрипт словаря возвращает опциональное значение, так как есть такая вероятность, что такого ключа в словаре может и не быть. В примере выше мы точно знаем, что number % 10 всегда вернет существующий ключ словаря digitNames, так что восклицательный знак используется для принудительного извлечения значения типа String в возвращаемом опциональном значении сабскрипта.

Строка, полученная из словаря digitNames, добавляется в начало переменной output, путем правильного формирования строковой версии числа наоборот.(Выражение number % 10 дает нам 6 для 16, 8 для 58 и 0 для 510).

Переменная number после вычисления остатка делится на 10. Так как тип значения Int, то наше число округляется вниз, таким образом 16 превращается в 1, 58 в 5, 510 в 51.

Процесс повторяется пока number /= 10 не станет равным 0, после чего строка output возвращается замыканием и добавляется к выходному массиву функции map(_:).

Использование синтаксиса последующих замыканий в примере выше аккуратно инкапсулирует функциональность замыкания сразу после функции map(_:), которой замыкание помогает, без необходимости заворачивания всего замыкания внутрь внешних круглых скобок функции map(_:).

 

Swift: 
4.0