Menu
Coddy logo textTech

Проброс ошибок

Часть раздела Логика и управление потоком путешествия по 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), позволяя вызывающей стороне решать, что делать.

challenge icon

Задание

Средне

Создайте небольшой конвейер из двух этапов, выбрасывающих ошибки.

Определите 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, перехватить каждую ветку, вывести
quiz iconПроверьте себя

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

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