Проброс ошибок
Часть раздела Логика и управление потоком путешествия по Swift на Coddy — урок 47 из 56.
Функция, выбрасывающая ошибку, может вызывать другие функции, выбрасывающие ошибки. Ошибка распространяется до ближайшего блока do/catch автоматически, ручной повторный выброс не требуется.
enum AuthError: Error { case badUser, badPass }
func loadUser(_ name: String) throws -> String {
if name.isEmpty { throw AuthError.badUser }
return name
}
func login(_ name: String, _ pass: String) throws -> String {
let u = try loadUser(name) // пробрасывает ошибку
if pass.count < 4 { throw AuthError.badPass }
return "hello \(u)"
}
do {
print(try login("", "abcd"))
} catch AuthError.badUser {
print("missing user")
} catch AuthError.badPass {
print("weak password")
}Читайте сверху вниз: login вызывает loadUser с использованием try. Если loadUser выбрасывает исключение, ошибка проходит мимо тела login и попадает во внешний catch. Вы пишете каждый шаг так, чтобы он быстро завершался с ошибкой (fail fast), позволяя вызывающей стороне решать, что делать.
Задание
СреднеСоздайте небольшой конвейер из двух этапов, выбрасывающих ошибки.
Определите StepError: Error с двумя случаями: negative, tooBig.
Определите parseSafe(_ s: String) throws -> Int: выбрасывает .negative, когда преобразованное целое число меньше 0, в противном случае возвращает его. (Предположим, что входные данные корректно преобразуются в число, вы обработали это в другом месте.)
Определите capStrict(_ n: Int) throws -> Int: выбрасывает .tooBig, когда n > 100, в противном случае возвращает n.
Определите processStep(_ s: String) throws -> Int, которая вызывает parseSafe, а затем capStrict, позволяя любой ошибке распространяться дальше.
Прочитайте одну строку ввода: список строк, разделенных запятыми. Для каждой из них вызовите processStep в блоке do/catch и выведите одну строку:
ok: <n>при успехеnegative, когдаparseSafeвыбросил ошибкуtoo big, когдаcapStrictвыбросил ошибку
Для входных данных 10,-1,200,42 вывод будет следующим:
ok: 10
negative
too big
ok: 42Шпаргалка
Функция, выбрасывающая ошибки (throwing function), может вызывать другие выбрасывающие ошибки функции с помощью try. Ошибки автоматически распространяются вверх до ближайшего блока do/catch:
enum AuthError: Error { case badUser, badPass }
func loadUser(_ name: String) throws -> String {
if name.isEmpty { throw AuthError.badUser }
return name
}
func login(_ name: String, _ pass: String) throws -> String {
let u = try loadUser(name) // ошибка распространяется выше, если она возникла
if pass.count < 4 { throw AuthError.badPass }
return "hello \(u)"
}
do {
print(try login("", "abcd"))
} catch AuthError.badUser {
print("missing user")
} catch AuthError.badPass {
print("weak password")
}Если loadUser выбрасывает ошибку, выполнение пропускает оставшуюся часть login и переходит непосредственно к внешнему блоку catch. Ручной повторный выброс ошибки не требуется.
Попробуйте сами
let parts = readLine()!.components(separatedBy: ",")
// TODO: enum StepError; parseSafe; capStrict; processStep;
// для каждой части выполнить/попробовать processStep, перехватить каждую ветку, вывести
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Логика и управление потоком
1Строки в деталях
Подсчет и индексыРегистр и удаление пробеловПоиск в строкахРазделение и объединениеЗамена подстрокИтоги — Проверка имени пользователя4Множества
Создание множествОбъединение и пересечениеРазность и симметрическая разностьПодмножество и надмножествоИтоги — Фильтр тегов7Проект — Трекер привычек
Обзор проектаОтметить выполнение10Проект — Движок викторины
Обзор проектаЗадаем вопросы2Диапазоны и шаги
Закрытые и полуоткрытыеШагМетоды диапазоновДиапазоны в SwitchИтоги: Сетка календаря3Словари
Объявление словарейБезопасный поискОбновление словарейИтерация по словарямГруппировка значенийИтоги — Инвентарь6Функции высшего порядка, часть 2
compactMapflatMapsorted(by:)Создание конвейеровПовторение — Таблица лидеров9Обработка ошибок
throws и Errordo, try, catchtry? и try!Проброс ошибокПовторение — Безопасный калькулятор