Error unions и try
Автомат выдаёт либо билет, либо сообщение «недостаточно средств». Обе карточки отвечают на запрос, но оплачивать поездку сообщением нельзя. Функция с ошибкой устроена так же: результат надо сначала разделить на успешный и неуспешный путь.
Мы читаем номер этажа из числа. В здании только этажи от 1 до 12. Если вход 0 или 20, функция не должна превращать его в случайный допустимый этаж.
Одна мысль урока
Тип E!T содержит успешное T или ошибку E; try передаёт ошибку вызывающему.
Опора из прошлого урока: Массивы и многоуказатели.
От картинки к записи
Объединение с ошибкой
записывают E!T. В нашем примере FloorError!u8 означает номер этажа либо error.InvalidFloor.
Слева от восклицательного знака набор ошибок, справа тип успешного значения. Это не исключение,
которое возникает где угодно незаметно для сигнатуры.
Набор ошибок
позволяет договориться о причинах неуспеха. Имена вроде InvalidFloor объясняют проблему лучше, чем
число -1. Одна функция может использовать небольшой явный набор, другая вывести его из тела записью
!u8. Для учебного примера явная запись особенно удобна: видны все пути.
Успешное значение возвращается через обычный return floor, ошибка через return error.InvalidFloor. У вызывающего обе возможности остаются в одном результате. Операция try раскрывает успех и немедленно возвращает ошибку из текущей функции при неуспехе. Поэтому текущая функция тоже должна иметь тип результата, допускающий эту ошибку.
Само слово try не исправляет ошибку. Оно не повторяет попытку, не печатает сообщение и не подставляет значение по умолчанию. Оно выбирает очень конкретный путь: вернуть неуспех выше. Для обработки на месте существует catch, который изучим следующим уроком. Сегодня полезно не смешивать ответственность уровней.
В примере doubleFloor вызывает проверку, затем умножает уже корректный номер. Для входа 4 получает 8. Для входа 20 строка умножения вообще не выполняется. Это важный порядок: сначала разбор допустимости, потом действия с успешным значением. Если поменять порядок, может появиться неверная арифметика ещё до проверки.
Ошибки отличаются от остановок из-за нарушенного договора. InvalidFloor ожидается для неподходящего пользовательского ввода. Выход за границы массива или чтение неинициализированных байтов не становится такой ошибкой автоматически. Нельзя поставить try перед любым выражением и получить защиту от всех проблем.
Тесты умеют проверять обе стороны. expectEqual сравнивает раскрытый успешный результат, expectError ожидает определённую ошибку и сам возвращает ошибку проверки, если ожидание не совпало. try перед expectError относится к результату проверки, а не принимает неправильный номер этажа за успех.
премиум-урок
Продолжение в премиуме: 1 200 ₽ в месяц или 10 000 ₽ в год. Вместе с ним серверные проверки задач и школьные токены AI-коуча.
Оплата пока не подключена: премиум и курсы открываются промокодом.