Rust
Обработка ошибок с Result и оператором ?
Собственный тип ошибки, From-конверсии и распространение ошибок через ?.
Код
use std::fmt;
use std::fs;
use std::num::ParseIntError;
#[derive(Debug)]
enum ConfigError {
Io(std::io::Error),
Parse(ParseIntError),
Missing(String),
}
impl fmt::Display for ConfigError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ConfigError::Io(e) => write!(f, "ошибка чтения: {e}"),
ConfigError::Parse(e) => write!(f, "ошибка разбора числа: {e}"),
ConfigError::Missing(key) => write!(f, "отсутствует параметр: {key}"),
}
}
}
impl std::error::Error for ConfigError {}
// Автоматическая конверсия для оператора ?
impl From<std::io::Error> for ConfigError {
fn from(e: std::io::Error) -> Self { ConfigError::Io(e) }
}
impl From<ParseIntError> for ConfigError {
fn from(e: ParseIntError) -> Self { ConfigError::Parse(e) }
}
fn read_port(path: &str) -> Result<u16, ConfigError> {
let content = fs::read_to_string(path)?; // io::Error → ConfigError
let line = content
.lines()
.find(|l| l.starts_with("port="))
.ok_or_else(|| ConfigError::Missing("port".into()))?;
let port = line.trim_start_matches("port=").trim().parse::<u16>()?;
Ok(port)
}
fn main() {
match read_port("app.conf") {
Ok(port) => println!("Порт: {port}"),
Err(e) => eprintln!("Не удалось прочитать конфигурацию: {e}"),
}
}