Свои типы ошибок
В Rust можно создавать собственные типы ошибок с помощью
перечислений (enum) или структур (struct).
Это даёт возможность точно описать, какие ошибки могут
возникнуть в программе, и обрабатывать их отдельно.
Обычно собственный тип ошибки реализует трейты
Debug, Display и Error, что позволяет
использовать его совместно с оператором ? и
стандартными средствами обработки ошибок.
Синтаксис
#[derive(Debug)]
enum MyError
{
Variant1,
Variant2,
}
impl std::fmt::Display for MyError
{
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result
{
match self
{
MyError::Variant1 => write!(f, "error variant 1"),
MyError::Variant2 => write!(f, "error variant 2"),
}
}
}
impl std::error::Error for MyError {}
Пример
Давайте создадим собственный тип ошибки с двумя вариантами и функцией, которая возвращает ошибку при определённом условии:
use std::fmt;
#[derive(Debug)]
enum MyError
{
EmptyInput,
TooShort,
}
impl fmt::Display for MyError
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
{
match self
{
MyError::EmptyInput => write!(f, "input is empty"),
MyError::TooShort => write!(f, "input is too short"),
}
}
}
impl std::error::Error for MyError {}
fn check(s: &str) -> Result<(), MyError>
{
if s.is_empty()
{
return Err(MyError::EmptyInput);
}
if s.len() < 3
{
return Err(MyError::TooShort);
}
Ok(())
}
fn main()
{
let res = check("ab");
println!("{:?}", res);
}
Результат выполнения кода:
Err(TooShort)
Пример
Давайте обработаем собственную ошибку с помощью
match и выведем понятное сообщение:
use std::fmt;
#[derive(Debug)]
enum MyError
{
EmptyInput,
TooShort,
}
impl fmt::Display for MyError
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
{
match self
{
MyError::EmptyInput => write!(f, "input is empty"),
MyError::TooShort => write!(f, "input is too short"),
}
}
}
impl std::error::Error for MyError {}
fn check(s: &str) -> Result<(), MyError>
{
if s.is_empty()
{
return Err(MyError::EmptyInput);
}
if s.len() < 3
{
return Err(MyError::TooShort);
}
Ok(())
}
fn main()
{
match check("abcde")
{
Ok(()) => println!("ok"),
Err(e) => println!("error: {}", e),
}
}
Результат выполнения кода:
"ok"
Пример
Давайте используем собственный тип ошибки вместе с
оператором ? для проброса ошибки из функции:
use std::fmt;
#[derive(Debug)]
enum MyError
{
EmptyInput,
TooShort,
}
impl fmt::Display for MyError
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
{
match self
{
MyError::EmptyInput => write!(f, "input is empty"),
MyError::TooShort => write!(f, "input is too short"),
}
}
}
impl std::error::Error for MyError {}
fn check(s: &str) -> Result<usize, MyError>
{
if s.is_empty()
{
return Err(MyError::EmptyInput);
}
if s.len() < 3
{
return Err(MyError::TooShort);
}
Ok(s.len())
}
fn run(s: &str) -> Result<usize, MyError>
{
let len = check(s)?;
Ok(len * 2)
}
fn main()
{
let res = run("abcde");
println!("{:?}", res);
}
Результат выполнения кода:
Ok(10)