不灭的焱

革命尚未成功,同志仍须努力 下载Java21

作者:AlbertWen  添加时间:2026-07-19 20:57:42  修改时间:2026-07-27 05:36:07  分类:01.Rust编程  编辑

目录

自定义错误类型示例

文件 src\lib.rs 内容如下:

use std::{env, fs, path::PathBuf};

use serde::Deserialize;

/// 应用配置
#[derive(Debug, Clone, Deserialize)]
pub struct AppConfig {
    pub server: ServerConfig,
    pub database: DatabaseConfig,
    pub auth: AuthConfig,
}

/// 服务器配置
#[derive(Debug, Clone, Deserialize)]
pub struct ServerConfig {
    pub addr: String,
}

/// 数据库配置
#[derive(Debug, Clone, Deserialize)]
pub struct DatabaseConfig {
    pub url: String,
}

/// 认证配置
#[derive(Debug, Clone, Deserialize)]
pub struct AuthConfig {
    pub jwt_secret: String,
}

/// 加载应用配置
impl AppConfig {
    pub fn load() -> Result<Self, ConfigError> {
        // 从环境变量中获取环境名称,如:dev/test/prod,默认值为 dev
        let env_name = env::var("APP_ENV").unwrap_or_else(|_| "dev".to_string());
        let path = PathBuf::from("config").join(format!("env_{env_name}.toml"));
        let content = fs::read_to_string(&path).map_err(|source| ConfigError::Read {
            path: path.clone(),
            source,
        })?;
        let mut config: AppConfig =
            toml::from_str(&content).map_err(|source| ConfigError::Parse {
                path: path.clone(),
                source,
            })?;

        if let Ok(addr) = env::var("FUYO_API_ADDR") {
            config.server.addr = addr;
        }
        if let Ok(url) = env::var("DATABASE_URL") {
            config.database.url = url;
        }
        if let Ok(secret) = env::var("FUYO_JWT_SECRET") {
            config.auth.jwt_secret = secret;
        }

        config.validate()?;
        Ok(config)
    }

    fn validate(&self) -> Result<(), ConfigError> {
        if self.server.addr.trim().is_empty() {
            return Err(ConfigError::Invalid("server.addr 不能为空"));
        }
        if self.database.url.trim().is_empty() {
            return Err(ConfigError::Invalid("database.url 不能为空"));
        }
        if self.auth.jwt_secret.trim().is_empty() {
            return Err(ConfigError::Invalid("auth.jwt_secret 不能为空"));
        }
        Ok(())
    }
}

#[derive(Debug)]
pub enum ConfigError {
    /// 读取配置文件失败
    Read {
        path: PathBuf,
        source: std::io::Error,
    },
    /// 解析配置文件失败
    Parse {
        path: PathBuf,
        source: toml::de::Error,
    },
    /// 配置错误
    Invalid(&'static str),
}

impl std::fmt::Display for ConfigError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Read { path, source } => {
                write!(f, "读取配置文件 {} 失败: {source}", path.display())
            }
            Self::Parse { path, source } => {
                write!(f, "解析配置文件 {} 失败: {source}", path.display())
            }
            Self::Invalid(message) => write!(f, "配置错误: {message}"),
        }
    }
}

impl std::error::Error for ConfigError {}

 

AI提问:为什么是空实现:impl std::error::Error for ConfigError { }    ?

AI回复:

我来查看这段代码的上下文,了解 ConfigError 的定义和实现细节。

代码分析

这段代码 impl std::error::Error for ConfigError {} 的作用是为自定义错误类型 ConfigError 实现 Rust 标准库的 Error trait。

为什么是空实现?

这是 Rust 1.41+ 的语言特性。在 Rust 1.41 之前,std::error::Error trait 需要实现一个必需的方法 description(&self) -> &str。但从 Rust 1.41 开始:

  1. description() 方法被标记为 #[deprecated],并提供了默认实现(基于 Display trait)
  2. 所有 Error trait 的方法都变成了可选的,都有默认实现

因此,只需要这样的空实现块,编译器就会自动为 ConfigError 生成所有 Error trait 方法的默认实现。

【重点】关键依赖关系

Error trait 的默认实现依赖于 ConfigError 已经实现了另外两个 trait:

必需 trait 实现位置 作用
std::fmt::Debug 第 75 行 #[derive(Debug)] 支持调试输出
std::fmt::Display 第 91-103 行 支持用户友好的错误消息格式化

这样做的好处

实现 std::error::Error trait 后,ConfigError 获得以下能力:

  1. 可以与 ? 操作符配合使用:在返回 Result<T, impl std::error::Error> 的函数中传播错误
  2. 支持错误链(Error Chain)