Menu
Coddy logo textTech

Захват значений

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

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

func makeCounter() -> () -> Int {
    var count = 0
    return {
        count += 1
        return count
    }
}

let next = makeCounter()
print(next())                    // 1
print(next())                    // 2
print(next())                    // 3

Каждый вызов makeCounter дает вам совершенно новый count, поэтому два счетчика никогда не разделяют состояние:

let a = makeCounter()
let b = makeCounter()
print(a())                       // 1
print(b())                       // 1
print(a())                       // 2

Захват переменных — это то, что делает замыкания более мощными, чем обычные функции: они несут в себе состояние. Вы увидите тот же прием в JavaScript, Python и многих других языках.

challenge icon

Задание

Средне

Создайте небольшую фабрику счетчиков.

Определите функцию makeCounter(start: Int, step: Int), которая возвращает замыкание типа () -> Int. Каждый вызов замыкания возвращает следующее значение: первый вызов возвращает start, следующий возвращает start + step, затем start + 2*step и так далее.

Прочитайте три целых числа из входных данных: start, step и n. Создайте счетчик с параметрами start и step, затем вызовите его n раз и выведите каждый результат на отдельной строке.

Для входных данных 5 / 3 / 4 вывод будет следующим:

5
8
11
14

Шпаргалка

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

func makeCounter() -> () -> Int {
    var count = 0
    return {
        count += 1
        return count
    }
}

let next = makeCounter()
print(next()) // 1
print(next()) // 2

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

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

let start = Int(readLine()!)!
let step = Int(readLine()!)!
let n = Int(readLine()!)!

// TODO: makeCounter(start:step:) -> () -> Int, которая захватывает текущее значение
// затем вызовите её n раз и выведите каждый результат
quiz iconПроверьте себя

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

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