Menu
Coddy logo textTech

Возврат замыканий

Часть раздела Логика и управление потоком путешествия по Swift на Coddy — урок 41 из 56.

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

func multiplier(_ k: Int) -> (Int) -> Int {
    return { n in n * k }
}

let triple = multiplier(3)
let tenfold = multiplier(10)
print(triple(4))                  // 12
print(tenfold(4))                 // 40

Возвращаемое замыкание захватывает k, поэтому каждый вызов multiplier(...) создает совершенно новое замыкание со своим собственным k.

Этот паттерн является основой кода «стратегия» в Swift: напишите функцию, которая принимает конфигурацию и возвращает замыкание, а затем передайте это замыкание в map, filter, sorted(by:) или в любое другое место, где ожидается значение в форме функции.

challenge icon

Задание

Средне

Создайте две фабрики замыканий:

  • greaterThan(_ k: Int) -> (Int) -> Bool: возвращает предикат, который принимает значение true, когда его аргумент строго больше k
  • scaleBy(_ k: Int) -> (Int) -> Int: возвращает функцию, которая умножает свой аргумент на k

Прочитайте три строки:

  1. Целое число threshold
  2. Целое число scale
  3. Список целых чисел через запятую, nums

Выведите три строки:

  1. Числа выше порога (отфильтруйте с помощью замыкания из greaterThan), разделенные ,
  2. Те же числа, масштабированные (преобразованные с помощью scaleBy), разделенные ,
  3. Количество чисел, прошедших фильтрацию

Для входных данных 5 / 3 / 2,7,3,8,9 результатом будет:

7,8,9
21,24,27
3

Шпаргалка

Фабрика замыканий — это функция, которая захватывает параметр и возвращает новое замыкание, настроенное с его помощью:

func multiplier(_ k: Int) -> (Int) -> Int {
    return { n in n * k }
}

let triple = multiplier(3)
print(triple(4))   // 12

Каждый вызов создает совершенно новое замыкание со своим собственным захваченным значением k. Возвращаемые замыкания можно передавать напрямую в map, filter, sorted(by:) и т. д.:

func greaterThan(_ k: Int) -> (Int) -> Bool {
    return { n in n > k }
}

let nums = [2, 7, 3, 8, 9]
let filtered = nums.filter(greaterThan(5))  // [7, 8, 9]
let scaled = filtered.map(multiplier(3))    // [21, 24, 27]

Попробуйте сами

let threshold = Int(readLine()!)!
let scale = Int(readLine()!)!
let nums = readLine()!.components(separatedBy: ",").map { Int($0)! }

// TODO: greaterThan, scaleBy; filter, затем map; вывести через разделитель и количество
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Логика и управление потоком