Вы должны определить свой собственный тип ошибки, который включает все возможные ошибки, которые могут произойти:
#[derive(Debug)]
enum Error {
Io(io::Error),
ParseInt(num::ParseIntError)
}
impl From<io::Error> for Error {
fn from(other: io::Error) -> Error {
Error::Io(other)
}
}
impl From<num::ParseIntError> for Error {
fn from(other: num::ParseIntError) -> Error {
Error::ParseInt(other)
}
}
Преобразования From
позволяют оператору ?
работать должным образом.
Вы можете сэкономить много времени на вводе текста, используя один из нескольких ящиков, которые создадут для вас шаблон. Некоторые популярные: thiserror и snafu .
Я предпочитаю thiserror
, потому что он добавляет только те реализации, которые вы в противном случае написали бы сами, и, если вы пишете библиотеку, он прозрачен для пользователей вашей библиотеки. snafu
, возможно, более мощный - он генерирует намного больше кода, но самоуверен в том, что он генерирует, поэтому вам нужно будет привыкнуть к его парадигме, чтобы в полной мере использовать его, и концепции snafu станут частью API вашей библиотеки.
Используя thiserror
, приведенный выше код сокращается до:
use thiserror::Error;
#[derive(Debug, Error)]
enum Error {
#[error("IO Error: {0})]
Io(#[from] io::Error),
#[error("ParseInt Error: {0})]
ParseInt(#[from] num::ParseIntError)
}
Обратите внимание, что это также генерирует Display
реализации, которые я не включил выше.