Anyhow Error Handler
Суть
Библиотека работы с ошибками - https://docs.rs/anyhow/latest/anyhow/
- Использует единый тип Error для всех ошибок;
- Добавляет контекст к ошибкам;
- Поддержка backtrace для debug;
Особенность применения:
- Для работы с ошибками в ПРИЛОЖЕНИЯХ (binary)!
- В библиотеках требуется получать на выходе конкретный тип ошибки, поэтому там применяется thiserror.
Установка
Использование
Anyhow создаёт алиас наподобие Result<T> = Result<T, Box<dyn Error>>, чтобы скрыть тип ошибок и сделать его универсальным.
Пример неудачного чтения файла:
Result<T>становится алиасом кResult<T, anyhow::Error>;Context,with_context()позволяет добавить подробности к ошибке, в случае неуспеха функции чтенияread_to_string();- Оператор
?выносит ошибку вверх, при этом авто-конвертирует её тип вanyhow::Error.
Замена Box<dyn> с контекстом
Возьмём пример, в котором чтение файла std::fs::read_to_string() (может быть неудачным), далее дешифровка его контента с помощью base64 decode() (может не получиться) в цепочку байт, из которой формируется строка String::from_utf8() (может не получиться). Все эти три потенциальных ошибки имеют разный тип.
Один способ все три их принять на одну функцию, это с помощью Box<dyn std::error::Error>>, потому что все 3 ошибки применяют std::error::Error.
Подход рабочий, но при срабатывании одной из трёх ошибок, судить о происхождении проблемы можно будет лишь по сообщению внутри ошибки.
В случае применения Anyhow, можно заменить им Box<dyn>, при этом сразу добавить контекстные сообщения, которое поможет понять место:
Замена map_err()
map_err() - это универсальный метод из стандартной библиотеки, который работает с любым Result. context() - это метод из anyhow, специально созданный для удобного добавления контекста к ошибкам.
context() принимает замыкание (closure), которое выполняется только при ошибке. Это важно для ресурсоемких операций:
with_context() - вариант context() с ленивым вычислением, идеален для дорогих операций вроде форматирования строк.