Spec-Zone .ru
спецификации, руководства, описания, API

Библиотека разработчика XCode

Разработчик

Swift язык программирования

iBook
На этой странице

Закрытия

Закрытия являются автономными блоками функциональности, которая может раздаваться и использоваться в Вашем коде. Закрытия в Swift подобны блокам в C и Objective C и лямбдам в других языках программирования.

Закрытия могут получить и сохранить ссылки на любые константы и переменные от контекста, в котором они определяются. Это известно как закрывающийся по тем константам и переменным, отсюда имя «закрытия». Swift обрабатывает все управление памятью получения для Вас.

Глобальные и вложенные функции, как представлено в Функциях, являются фактически особыми случаями закрытий. Закрытия принимают одну из трех форм:

  • Глобальные функции являются закрытиями, имеющими имя и не получающими значений.

  • Вложенные функции являются закрытиями, которые имеют имя и могут получить значения от их функции включения.

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

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

  • Выведение значения параметра и возвращаемого значения вводит от контекста

  • Неявные возвраты из закрытий отдельного выражения

  • Краткие имена параметра

  • Запаздывающий синтаксис закрытия

Выражения закрытия

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

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

Сортированная функция

Стандартная библиотека Swift обеспечивает вызванную функцию sorted, который сортирует массив значений известного типа, на основе вывода закрытия сортировки, которое Вы обеспечиваете. Как только это завершает процесс сортировки, sorted функционируйте возвращает новый массив того же типа и размера как старый, с его элементами в корректном сортированном порядке. Исходный массив не изменяется sorted функция.

Примеры выражения закрытия ниже используют sorted функционируйте для сортировки массива String значения в обратном алфавитном порядке. Вот начальный массив, который будет сортирован:

  • let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]

sorted функция берет два параметра:

  • Массив значений известного типа.

  • Закрытие, берущее два параметра того же типа как содержание массива и возвращающее a Bool значение, чтобы сказать, должно ли первое значение появиться прежде или после второго значения один раз значения, сортируется. Закрытие сортировки должно возвратиться true если первое значение должно появиться перед вторым значением, и false иначе.

Этот пример сортирует массив String значения, и таким образом, закрытие сортировки должно быть функцией типа (String, String) -> Bool.

Один способ обеспечить закрытие сортировки состоит в том, чтобы записать нормальную функцию корректного типа, и передать его в как sorted второй параметр функции:

  • func backwards(s1: String, s2: String) -> Bool {
  • return s1 > s2
  • }
  • var reversed = sorted(names, backwards)
  • // reversed is equal to ["Ewa", "Daniella", "Chris", "Barry", "Alex"]

Если первая строка (s1) больше, чем вторая строка (s2), backwards функция возвратится true, указание этого s1 должен появиться прежде s2 в сортированном массиве. Для символов в строках, “больше, чем” означает, “появляется позже в алфавите, чем”. Это означает что буква "B" “больше, чем” буква "A", и строка "Tom" больше, чем строка "Tim". Это дает обратный алфавитный вид, с "Barry" быть помещенным прежде "Alex", и т.д.

Однако это - довольно многоречивый способ записать то, что является по существу функцией отдельного выражения (a > b). В этом примере было бы предпочтительно записать закрытию сортировки встроенный, использующий синтаксис выражения закрытия.

Синтаксис выражения закрытия

Синтаксис выражения закрытия имеет следующую общую форму:

  • { (parameters) -> return type in
  •     statements
  • }

Синтаксис выражения закрытия может использовать постоянные параметры, переменные параметры, и inout параметры. Значения по умолчанию не могут быть предоставлены. Параметры Variadic могут использоваться, если Вы называете variadic параметр и помещаете его в последний раз в список параметров. Кортежи могут также использоваться в качестве типов параметра и типов возврата.

Пример ниже шоу версия выражения закрытия backwards функция от ранее:

  • reversed = sorted(names, { (s1: String, s2: String) -> Bool in
  • return s1 > s2
  • })

Обратите внимание на то, что объявление параметров и типа возврата для этого встроенного закрытия идентично объявлению от backwards функция. В обоих случаях это записано как (s1: String, s2: String) -> Bool. Однако для встроенного выражения закрытия, параметры и тип возврата записаны в изогнутых фигурных скобках, не за пределами них.

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

Поскольку организация закрытия так коротка, это может даже быть записано на одной строке:

  • reversed = sorted(names, { (s1: String, s2: String) -> Bool in return s1 > s2 } )

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

Выведение типа от контекста

Поскольку закрытие сортировки передается как параметр функции, Swift может вывести типы своих параметров и тип значения, которое это возвращает из типа sorted второй параметр функции. Этот параметр ожидает функцию типа (String, String) -> Bool. Это означает что (String, String) и Bool типы не должны быть записаны как часть определения выражения закрытия. Поскольку все типы могут быть выведены, стрелка возврата (->) и круглые скобки вокруг имен параметров могут также быть опущены:

  • reversed = sorted(names, { s1, s2 in return s1 > s2 } )

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

Тем не менее, можно все еще сделать типы явными, при необходимости и выполнение так мотивировано, если оно избегает неоднозначности для читателей Вашего кода. В случае sorted функция, цель закрытия ясна из факта, что сортировка имеет место, и безопасно для читателя предположить, что закрытие, вероятно, будет работать с String значения, потому что это помогает с сортировкой массива строк.

Неявные возвраты из закрытий отдельного выражения

Закрытия отдельного выражения могут неявно возвратить результат своего отдельного выражения путем исключения return ключевое слово от их объявления, как в этой версии предыдущего примера:

  • reversed = sorted(names, { s1, s2 in s1 > s2 } )

Здесь, функциональный тип sorted второй параметр функции проясняет это a Bool значение должно быть возвращено закрытием. Поскольку организация закрытия содержит отдельное выражение (s1 > s2) это возвращает a Bool значение, нет никакой неоднозначности, и return ключевое слово может быть опущено.

Краткие имена параметра

Swift автоматически обеспечивает краткие имена параметра для встраивания закрытий, которые могут использоваться для обращения к значениям параметров закрытия именами $0, $1, $2, и т.д.

При использовании этих кратких имен параметра в выражении закрытия можно опустить список аргументов закрытия из его определения, и число и тип кратких имен параметра будут выведены из ожидаемого функционального типа. in ключевое слово может также быть опущено, потому что выражение закрытия составлено полностью его организации:

  • reversed = sorted(names, { $0 > $1 } )

Здесь, $0 и $1 обратитесь к закрытию, первому и второму String параметры.

Функции оператора

Существует фактически еще более короткий способ записать выражение закрытия выше. Swift String тип определяет свою специфичную для строки реализацию большего - чем оператор (>) как функция, имеющая два параметра типа String, и возвращает значение типа Bool. Это точно соответствует функциональный тип, необходимый для sorted второй параметр функции. Поэтому можно просто передать в большем - чем оператор, и Swift выведет, что Вы хотите использовать его специфичную для строки реализацию:

  • reversed = sorted(names, >)

Для больше о функциях оператора, посмотрите Функции Оператора.

Запаздывающие закрытия

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

  • func someFunctionThatTakesAClosure(closure: () -> ()) {
  • // function body goes here
  • }
  • // here's how you call this function without using a trailing closure:
  • someFunctionThatTakesAClosure({
  • // closure's body goes here
  • })
  • // here's how you call this function with a trailing closure instead:
  • someFunctionThatTakesAClosure() {
  • // trailing closure's body goes here
  • }

Сортирующее строку закрытие от раздела Closure Expression Syntax выше может быть записано за пределами sorted круглые скобки функции как запаздывающее закрытие:

  • reversed = sorted(names) { $0 > $1 }

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

После применения предоставленного закрытия к каждому элементу матрицы, 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(_:) метод как запаздывающее закрытие. Обратите внимание на то, что вызов к numbers.map не должен включать круглые скобки после map, потому что map(_:) метод имеет только один параметр, и тот параметр предоставлен как запаздывающее закрытие:

  • let strings = numbers.map {
  • (var number) -> String in
  • var output = ""
  • while number > 0 {
  • output = digitNames[number % 10]! + output
  • number /= 10
  • }
  • return output
  • }
  • // strings is inferred to be of type [String]
  • // its value is ["OneSix", "FiveEight", "FiveOneZero"]

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

В этом примере, закрытие number параметр определяется как переменный параметр, как описано в Константе и Переменные Параметры, так, чтобы значение параметра могло быть изменено в организации закрытия, вместо того, чтобы объявить новую локальную переменную и присвоить переданный number оцените ему. Выражение закрытия также указывает тип возврата String, указать тип, который будет сохранен в отображенном выходном массиве.

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

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

number переменная тогда разделена на 10. Поскольку это - целое число, это округляется в меньшую сторону во время подразделения, таким образом, 16 становится 1, 58 становится 5, и 510 становится 51.

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

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

Получение значений

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

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

Вот пример вызванной функции makeIncrementer, который содержит вызванную вложенную функцию incrementer. Вложенный incrementer функционируйте получает два значения, runningTotal и amount, от его окружающего контекста. После получения этих значений, incrementer возвращается makeIncrementer как постепенно увеличивающееся закрытие runningTotal amount каждый раз это вызывают.

  • func makeIncrementer(forIncrement amount: Int) -> () -> Int {
  • var runningTotal = 0
  • func incrementer() -> Int {
  • runningTotal += amount
  • return runningTotal
  • }
  • return incrementer
  • }

Тип возврата makeIncrementer () -> Int. Это означает, что возвращает функцию, а не простое значение. Функция, которую это возвращает, не имеет никаких параметров и возвращается Int оцените каждый раз, когда это вызывают. Чтобы изучить, как функции могут возвратить другие функции, посмотрите Функциональные Типы как Типы Возврата.

makeIncrementer функция определяет вызванную целочисленную переменную runningTotal, сохранить текущее рабочее общее количество инкрементора, который будет возвращен. Эта переменная инициализируется со значением 0.

makeIncrementer функция имеет сингл Int параметр с внешним именем forIncrement, и локальное имя amount. Значение аргумента, переданное этому параметру, указывает сколько runningTotal должен быть постепенно увеличен к каждому разу, когда возвращенная функция инкрементора вызвана.

makeIncrementer определяет вызванную вложенную функцию incrementer, который выполняет фактическое постепенное увеличение. Эта функция просто добавляет amount к runningTotal, и возвращает результат.

Когда рассмотрено в изоляции, вложенном incrementer функция могла бы казаться необычной:

  • func incrementer() -> Int {
  • runningTotal += amount
  • return runningTotal
  • }

incrementer функция не имеет никаких параметров, и все же она относится к runningTotal и amount из его тела функции. Это делает это путем получения существующих значений runningTotal и amount от его окружающей функции и использования их в его собственном теле функции.

Поскольку это изменяет runningTotal переменная каждый раз это вызывают, incrementer получает ссылку на ток runningTotal переменная, и не только копия ее начального значения. Получение ссылки гарантирует это runningTotal не исчезает когда вызов к makeIncrementer концы, и гарантируют это runningTotal доступно в следующий раз incrementer функция вызвана..

Однако, потому что это не изменяет amount, и amount не видоизменен снаружи, incrementer фактически получения и хранилища копия значения, сохраненного в amount. Это значение сохранено вместе с новым incrementer функция.

Вот пример makeIncrementer в действии:

  • let incrementByTen = makeIncrementer(forIncrement: 10)

Этот пример устанавливает вызванную константу incrementByTen относиться к добавляющей функции инкрементора 10 к runningTotal переменная каждый раз это вызывают. Вызывание функции многократно показывает это поведение в действии:

  • incrementByTen()
  • // returns a value of 10
  • incrementByTen()
  • // returns a value of 20
  • incrementByTen()
  • // returns a value of 30

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

  • let incrementBySeven = makeIncrementer(forIncrement: 7)
  • incrementBySeven()
  • // returns a value of 7

Вызов исходного инкрементора (incrementByTen) снова продолжает постепенно увеличивать его собственное runningTotal переменная, и не влияет на переменную, полученную incrementBySeven:

  • incrementByTen()
  • // returns a value of 40

Закрытия являются ссылочными типами

В примере выше, incrementBySeven и incrementByTen константы, но закрытия, к которым относятся эти константы, все еще в состоянии постепенно увеличиться runningTotal переменные, которые они получили. Это вызвано тем, что функции и закрытия являются ссылочными типами.

Каждый раз, когда Вы присваиваете функцию или закрытие к константе или переменной, Вы фактически устанавливаете ту константу или переменные, чтобы быть ссылкой на функцию или закрытие. В примере выше, это - выбор закрытия это incrementByTen относится к этому, является постоянным, а не содержание самого закрытия.

Это также означает, что при присвоении закрытия двум различным константам или переменным обе из тех констант или переменных будут относиться к тому же закрытию:

  • let alsoIncrementByTen = incrementByTen
  • alsoIncrementByTen()
  • // returns a value of 50