defer с ошибками и ранним возвратом
Обеспечивайте очистку даже при выбросе ошибки или раннем возврате.
«defer с ошибками и ранним возвратом» — бесплатный урок Swift Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Swift Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Swift Academy содержит 4 уроков всего.
defer выполняется при возврате
Блок defer выполняется даже при досрочном выходе функции через return.
func check(_ value: Int) {
defer { print("cleanup ran") }
if value < 0 {
print("negative, returning early")
return
}
print("value is", value)
}
check(-5)Очистка на каждом пути
Независимо от того, какой return сработает, отложенная очистка выполняется ровно один раз.
func classify(_ n: Int) {
defer { print("done classifying") }
if n == 0 { print("zero"); return }
if n > 0 { print("positive"); return }
print("negative")
}
classify(0)defer выполняется при исключении
Когда функция выбрасывает исключение, зарегистрированные defers по-прежнему выполняются по мере выхода из областей видимости.
enum MyError: Error { case bad }
func risky(_ fail: Bool) throws {
defer { print("cleanup on the way out") }
if fail { throw MyError.bad }
print("no failure")
}
try? risky(true)Сочетание возврата и исключения
Независимо от того, возвращает ли функция управление обычным образом или выбрасывает исключение, срабатывает один и тот же defer.
enum E: Error { case oops }
func op(_ flag: Bool) throws -> Int {
defer { print("op finishing") }
if flag { throw E.oops }
return 42
}
let r = try? op(false)
print(r ?? -1)Очистка до распространения ошибки
defer выполняется до того, как выброшенная ошибка достигнет вызывающего кода, поэтому ресурсы освобождаются заранее.
enum E: Error { case fail }
func load(_ broken: Bool) throws {
print("open")
defer { print("close") }
if broken { throw E.fail }
print("read")
}
do {
try load(true)
} catch {
print("caught:", error)
}Защита с помощью defer
Распространённый шаблон: получить ресурс, отложить очистку, а затем использовать guard с досрочными возвратами, которые всё равно запускают очистку.
func process(_ items: [Int]) {
print("start")
defer { print("finished") }
guard !items.isEmpty else {
print("nothing to do")
return
}
print("processing", items.count, "items")
}
process([])defer и циклы с исключениями
defer внутри цикла выполняется в конце каждой итерации, даже если более поздняя инструкция выбрасывает исключение.
enum E: Error { case stop }
func loop() throws {
for i in 1...3 {
defer { print("end", i) }
if i == 2 { throw E.stop }
print("body", i)
}
}
try? loop()Порядок при досрочном возврате
Несколько defers по-прежнему выполняются в порядке LIFO при досрочном возврате.
func multi(_ skip: Bool) {
defer { print("A") }
defer { print("B") }
if skip { return }
print("body")
}
multi(true)Журналирование при сбое
Используйте defer, чтобы единообразно выполнить журналирование завершения или сбоя на всех путях выхода.
enum E: Error { case bad }
func attempt(_ fail: Bool) throws {
var success = false
defer { print("attempt success:", success) }
if fail { throw E.bad }
success = true
}
try? attempt(true)Восстановление состояния при исключении
defer идеально подходит для отмены временных изменений состояния при выбрасывании исключения операцией.
enum E: Error { case fail }
func transaction(_ fail: Bool) throws {
var inProgress = true
defer { inProgress = false; print("inProgress:", inProgress) }
if fail { throw E.fail }
print("committed")
}
try? transaction(true)Рекомендуемый подход
Полагаясь на defer для очистки, которая должна выполняться даже при досрочных возвратах и выброшенных ошибках, Вы предотвращаете утечки ресурсов на любом пути выхода.
enum E: Error { case x }
func safe(_ fail: Bool) throws {
print("acquire")
defer { print("release") }
if fail { throw E.x }
print("use")
}
try? safe(true)Быстрая проверка
Проверьте defer с ошибками и возвратами.
Итоги
defer выполняется при каждом выходе из области видимости, включая досрочный return и выброшенную ошибку, до распространения ошибки. Поэтому это надёжное место для очистки и восстановления состояния на всех путях выхода с сохранением порядка LIFO.
func f(_ skip: Bool) {
defer { print("cleanup") }
if skip { return }
print("work")
}
f(true)Часто задаваемые вопросы
Урок «defer с ошибками и ранним возвратом» бесплатный?
Да — полный текст урока «defer с ошибками и ранним возвратом» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Swift Academy, подпишись на CoddyKit PRO. Курс Swift Academy содержит 4 уроков всего.
Чему я научусь в уроке «defer с ошибками и ранним возвратом»?
Обеспечивайте очистку даже при выбросе ошибки или раннем возврате. Ты практикуешь Swift Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Swift Academy?
Предыдущий опыт не требуется. Swift Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «defer с ошибками и ранним возвратом»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Swift Academy?
Да. Каждый урок Swift Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Как работает defer
- Порядок выполнения нескольких блоков defer
- defer для освобождения ресурсов
- defer с ошибками и ранним возвратом