Возврат замыканий
Часть раздела Логика и управление потоком путешествия по 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:) или в любое другое место, где ожидается значение в форме функции.
Задание
СреднеСоздайте две фабрики замыканий:
greaterThan(_ k: Int) -> (Int) -> Bool: возвращает предикат, который принимает значениеtrue, когда его аргумент строго большеkscaleBy(_ k: Int) -> (Int) -> Int: возвращает функцию, которая умножает свой аргумент наk
Прочитайте три строки:
- Целое число
threshold - Целое число
scale - Список целых чисел через запятую,
nums
Выведите три строки:
- Числа выше порога (отфильтруйте с помощью замыкания из
greaterThan), разделенные, - Те же числа, масштабированные (преобразованные с помощью
scaleBy), разделенные, - Количество чисел, прошедших фильтрацию
Для входных данных 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; вывести через разделитель и количество
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Логика и управление потоком
1Строки в деталях
Подсчет и индексыРегистр и удаление пробеловПоиск в строкахРазделение и объединениеЗамена подстрокИтоги — Проверка имени пользователя4Множества
Создание множествОбъединение и пересечениеРазность и симметрическая разностьПодмножество и надмножествоИтоги — Фильтр тегов7Проект — Трекер привычек
Обзор проектаОтметить выполнение10Проект — Движок викторины
Обзор проектаЗадаем вопросы2Диапазоны и шаги
Закрытые и полуоткрытыеШагМетоды диапазоновДиапазоны в SwitchИтоги: Сетка календаря