Rust

Обработка ошибок с Result и оператором ?

Algonexys · 07.08.2026 · 👁 0

Собственный тип ошибки, 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}"),
    }
}