Menu
Coddy logo textTech

do, try, catch

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

Полная форма обработки ошибок — это do/try/catch:

enum DivError: Error { case byZero }

func divide(_ a: Int, _ b: Int) throws -> Int {
    if b == 0 { throw DivError.byZero }
    return a / b
}

do {
    let r = try divide(10, 2)
    print(r)                      // 5
} catch DivError.byZero {
    print("can't divide by zero")
} catch {
    print("unknown error")
}

try ставится перед любым вызовом, который может выбросить ошибку. Если вызов выбрасывает ошибку, управление переходит к соответствующему catch; в противном случае выполнение продолжается после блока do.

Несколько блоков catch выполняются сверху вниз, и срабатывает первое совпадение, точно так же, как в switch. Пустой catch в конце является универсальным обработчиком; он почти всегда нужен, чтобы компилятор был доволен.

challenge icon

Задание

Легко

Определите перечисление ParseError: Error с тремя вариантами: empty, notInteger и negative.

Определите функцию, выбрасывающую ошибку, parsePositive(_ s: String) throws -> Int, которая:

  • Выбрасывает .empty, если s после удаления пробелов пуста
  • Выбрасывает .notInteger, если s не может быть преобразована в Int
  • Выбрасывает .negative, если полученное значение < 0
  • В противном случае возвращает полученное значение

Считайте одну строку из stdin и вызовите parsePositive в блоке do/catch. Выведите:

  • got: <n> в случае успеха
  • error: empty, error: not integer или error: negative для каждого случая

Для входных данных 42 результатом будет got: 42. Для пустой строки — error: empty. Для abcerror: not integer.

Шпаргалка

Обработка ошибок в Swift использует do/try/catch. Определяйте ошибки с помощью перечисления (enum), соответствующего протоколу Error, помечайте функции, которые могут выбрасывать ошибки, ключевым словом throws и используйте throw для вызова ошибки:

enum DivError: Error { case byZero }

func divide(_ a: Int, _ b: Int) throws -> Int {
    if b == 0 { throw DivError.byZero }
    return a / b
}

do {
    let r = try divide(10, 2)
    print(r)                      // 5
} catch DivError.byZero {
    print("can't divide by zero")
} catch {
    print("unknown error")        // универсальный перехватчик
}
  • try должен предшествовать каждому вызову, который может выбросить ошибку.
  • Блоки catch сопоставляются сверху вниз; срабатывает первое совпадение.
  • Обычный блок catch в конце действует как универсальный перехватчик для всех остальных ошибок.

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

let line = readLine()!

// TODO: enum ParseError; func parsePositive(_:) throws -> Int;
// do/try/catch с тремя ветками плюс универсальный блок catch
quiz iconПроверьте себя

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

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