Эта страница описывает Топаз v5.17. Прежде чем считать её актуальной, сверьте поле version в /version.json со значением 5.17.
Результат: вы представите ожидаемое отсутствие и восстанавливаемую ошибку значениями, гарантируете очистку области и отличите оба случая от нарушения контракта во время выполнения.
Что нужно знать: завершите Данные и управление и научитесь прослеживать значение через if, match и for.
Сделайте неверный ввод ожидаемым результатом
Создайте failures-resources.tpz:
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")Проверьте и запустите файл:
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 finishedtoInt возвращает Option: Some(значение) означает, что целое число присутствует, а оставшийся случай покрывает отсутствие. разобратьМинуты превращает отсутствие и неположительное число в Result с понятным сообщением.
создатьЗадачу тоже возвращает Result. Постфиксный ? извлекает значение из Ok, а совместимый Err немедленно возвращает из текущей функции. Поэтому неверная задача не создаётся. проверить явно обрабатывает оба исхода.
defer принадлежит области, которая начала проверку. Успешный и неуспешный ввод проходят разные ветви, но строка завершения появляется после обоих. В функции, владеющей настоящим ресурсом, обязательную очистку точно так же помещают в область владельца.
Изучите нарушенный контракт
Теперь создайте intentional-fault.tpz:
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?
Показать ответ
Ноль попадёт в запасную ветвь и напечатает cannot add task: minutes must be a positive integer. Следующей строкой всё равно будет inspection finished, потому что defer выполняется при выходе из области проверить.
Готовы двигаться дальше, если
Вы можете объяснить, почему неверный текст становится Err, почему ? безопасен внутри создатьЗадачу, почему строка очистки появляется дважды и почему выход за границы — это fault, а не ожидаемый ввод.
Точные правила приведены в разделах Null, Option, Result и ошибки и Defer и ресурсы. Переходите к Первому приложению.