Обработка нескольких типов ошибок

Последнее обновление: 04.05.2021

Выше функция использовала один тип ошибки, что введен некорретный возвраст. Однако, что если мы захотим разграничить несколько различных ситуаций, которые могут вызывать ошибку. Например, мы могли бы определять отдельные ошибки при вводе некорректного возраста и некорректного имени пользователя. Рассмотрим возможную реализацию:

struct Person{ name: String, age:u8}
enum ErrorKind{
	InvalidAge(String),
	InvalidName(String)
}
struct PersonError {kind: ErrorKind}

fn create_person(username: &str, userage: u8) -> Result<Person, PersonError>{
	
	if username.len() < 3{
		Result::Err(
			PersonError{kind: ErrorKind::InvalidName(
				String::from("Некорректное имя. Длина имени должна быть больше 2-х символов")
			)}
		)
	}
	else if userage > 110{
		
		Result::Err(
			PersonError{kind: ErrorKind::InvalidAge(
				String::from("Некорректный возраст. Возраст должен быть меньше 110")
			)}
		) 
	}
	else{
		let new_person = Person{name: String::from(username), age: userage };
		Result::Ok(new_person)
	}
}

Здесь для представления ошибок определена структура PersonError, которая имеет одно поле - kind, которое описывает тип ошибки и представляет перечисление ErrorKind.

Теперь функция create_person возвращает объект Result<Person, PersonError>, а это значит, что в константу Err необходимо передать объект PersonError.

В коде функции в зависимости от типа некорретных данных в PersonError передается та или иная константа перечисления ErrorKind:

Result::Err(
			PersonError{kind: ErrorKind::InvalidName(
				String::from("Некорректное имя. Длина имени должна быть больше 2-х символов")
			)}
		)

Используем функцию create_person в функции main:

fn main() {
	
	let tom_result = create_person("To", 36);
	let tom = match tom_result{
		Ok(person) => person,
		Err(error) => match error.kind {
            ErrorKind::InvalidAge(message) => panic!("{}", message),
            ErrorKind::InvalidName(message) => panic!("{}", message)
		}
	};
	
	println!("Name: {}  Age: {}", tom.name, tom.age);
}

Для обработки конкретного типа ошибки применяются две конструкции match. В первой - внешней конструкции match узнаем, какой именно результат пришел из функции create_person:

let tom = match tom_result{
		Ok(person) => person,
		Err(error) => //.........
		}
	};

Если результат представляет константу Result::Ok, то получем и возвращем объект Person. И затем мы сможем к нему обращаться через переменную tom.

Если результат представляет константу Result::Err, то используем вторую - вложенную конструкцию match, чтобы определить конкретный тип ошибки - какую константу перечисления ErrorKind она представляет:

Err(error) => match error.kind {
            ErrorKind::InvalidAge(message) => panic!("{}", message),
            ErrorKind::InvalidName(message) => panic!("{}", message)
		}

Поскольку каждая константа перечисления ErrorKind хранит значение типа String (в программе выше это сообщение об ошибке), то мы его можем получить в переменную message и передать в макрос panic.

Пример работы программы при передаче некорректного имени:

ErrorKind и типы и обработка ошибок в Rust

И также мы можем сократить данный пример с помощью метода unwrap_or_else():

fn main() {
	
	let tom = create_person("Tov", 36).unwrap_or_else(|error| {
			match error.kind {
				ErrorKind::InvalidAge(message) => panic!("{}", message),
				ErrorKind::InvalidName(message) => panic!("{}", message)
			}
	});
	
	println!("Name: {}  Age: {}", tom.name, tom.age);
}
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850