Изучение Топаза

Ошибки и ресурсы

Обрабатывайте некорректный ввод с помощью Option, Result и постфиксного оператора ?, выполняйте очистку через defer и разберитесь с возникновением fault.

Результат: вы представите отсутствие значения и восстанавливаемую ошибку в виде значений, обеспечите очистку в области видимости и научитесь отличать эти случаи от нарушения контракта во время выполнения.

Что нужно знать: изучите раздел Данные и управление и научитесь отслеживать значения с помощью if, match и for.

Сделайте неверный ввод ожидаемым результатом

Создайте failures-resources.tpz:

TOPAZ
record УчебнаяЗадача {
    название: string,
    минуты: int,
}

function разобратьМинуты(текст: string) -> Result<int, string> {
    match toInt(текст) {
        case Some(значение) if значение > 0 => Ok(значение)
        case _ => Err("minutes must be a positive integer")
    }
}

function создатьЗадачу(название: string, текстМинут: string) -> Result<УчебнаяЗадача, string> {
    let минуты = разобратьМинуты(текстМинут)?
    Ok(УчебнаяЗадача { название: название, минуты: минуты })
}

function проверить(текстМинут: string) -> () {
    print("input: {текстМинут}")
    defer { print("inspection finished") }
    match создатьЗадачу("Build application", текстМинут) {
        case Ok(задача) => print("ready: {задача.название}, {задача.минуты} minutes")
        case Err(сообщение) => print("cannot add task: {сообщение}")
    }
}

проверить("25")
проверить("later")

Проверьте и запустите файл:

BASH
topaz check failures-resources.tpz
topaz run failures-resources.tpz

Некорректный ввод обрабатывается как обычные данные, поэтому процесс завершается штатно:

Вывод
input: 25
ready: Build application, 25 minutes
inspection finished
input: later
cannot add task: minutes must be a positive integer
inspection finished

toInt возвращает Option. Вариант Some(значение) означает наличие целого числа, а оставшаяся ветка обрабатывает его отсутствие. Функция разобратьМинуты преобразует отсутствие значения и неположительное число в Result с понятным сообщением.

создатьЗадачу также возвращает Result. Постфиксный оператор ? извлекает значение из Ok, а при наличии Err немедленно возвращает его из текущей функции. Поэтому некорректная задача не создаётся. Функция проверить явно обрабатывает оба исхода.

defer привязан к области видимости, в которой выполняется проверка. Успешный и некорректный ввод приводят к выполнению разных веток, однако итоговая строка выводится в обоих случаях. В функции, владеющей реальным ресурсом, очистку точно так же помещают в область видимости владельца.

Изучите нарушенный контракт

Теперь создайте intentional-fault.tpz:

TOPAZ
let задачи = ["Run first program", "Build application"]
print(задачи[2])

Команда topaz run intentional-fault.tpz завершается с ненулевым кодом:

Вывод
error[TPZ4001]: index 2 is out of bounds for an array of length 2
 --> intentional-fault.tpz:2:7
  |
2 | print(задачи[2])
  |       ^^^^^^^^^

Это fault, а не восстанавливаемый Err. Программа вышла за границы массива. Диагностическое сообщение указывает на нарушенный контракт и место в исходном коде, не пытаясь подставить отсутствующее значение.

Выбор: отсутствие, восстановление или fault?

Используйте Option, когда отсутствие значения — обычный исход. Используйте Result, если вызывающий код способен отреагировать на осмысленную ошибку, и ?, чтобы передать её через другой совместимый Result. Нарушение контракта выражается как fault. Независимо от этого выбора применяйте defer, когда область видимости должна выполнить очистку при любом выходе из неё.

Попробуйте

Добавьте в рабочую программу проверить("0"). Какая ветка сработает и появится ли строка из defer?

Показать ответ

Значение 0 попадёт в ветку по умолчанию и выведет cannot add task: minutes must be a positive integer. Следующей строкой всё равно выведется inspection finished, поскольку defer выполняется при выходе из области видимости проверить.

Готовы двигаться дальше, если

Вы можете объяснить, почему некорректный текст становится Err, почему ? допустим внутри создатьЗадачу, почему строка очистки появляется дважды и почему выход за границы — это fault, а не ожидаемый ввод.

Точные правила приведены в разделах Null, Option, Result и ошибки и Defer и ресурсы. Переходите к разделу Первое приложение.