Обработка ошибок и исключения в ООП
Суть
В классических ООП-языках (Java, C#, C++) ошибки — это исключения: объект выбрасывается, стек раскручивается до ближайшего catch, любой вызов может неявно прервать выполнение. В Swift подход другой: ошибка — это значение, а не исключение.
Как устроено в Swift
Error— пустой протокол; ошибки обычно описываютenumс associated values илиstruct.- Функция объявляет
throws; вызов обязан быть помеченtry. Нет скрытых путей выхода —tryвидно в коде. - Под капотом
throws— это обычный возврат через дополнительный регистр, без раскрутки стека и таблиц исключений: бросать ошибку дёшево. - Typed throws (Swift 6):
throws(PaymentError)— тип ошибки в сигнатуре,catchисчерпывающий, нет боксинга вany Error. Нетипизированныйthrowsэквивалентенthrows(any Error). Result<Success, Failure>хранит результат «на потом» (колбэки, Combine);try?превращает ошибку вnil,try!— в crash;deferвыполняет cleanup на любом пути выхода.NSExceptionиз Objective-C не ловится Swift-кодом — это баг, а не ошибка; то же проfatalError/precondition.
import Foundation
enum PaymentError: Error {
case insufficientFunds(missing: Decimal)
case cardExpired
}
// Typed throws (Swift 6): the error type is part of the signature.
func charge(_ amount: Decimal, balance: Decimal) throws(PaymentError) {
guard balance >= amount else {
throw .insufficientFunds(missing: amount - balance)
}
}
do {
try charge(100, balance: 30)
} catch .insufficientFunds(let missing) {
print("need \(missing) more") // need 70 more
} catch {
print("other: \(error)")
}
// Error as a value: Result keeps success/failure for later.
let result = Result { try charge(10, balance: 50) }
if case .failure(let e) = result { print(e) }
let maybe: Void? = try? charge(1, balance: 0) // nil on failure
print(maybe == nil) // true
На что смотрит интервьюер
- Разделение ожидаемых ошибок (сеть, валидация →
throws/Result) и ошибок программиста (нарушение инварианта →precondition, crash). - Typed throws нужны в библиотечном коде и в embedded/производительных местах; в прикладном коде
any Errorобычно достаточно. - Связь с async:
async throwsошибки проходят черезawaitтак же, как через обычный вызов;Taskхранит ошибку вResult-подобном.value.