rust-config配置读取

config用法

# 添加config库
cargo add config
cargo add serde --features derive

嵌套结构

test.toml配置文件

debug = false
fruits = ["apple", "banana", "cherry"]

[server]
[server.test]
host = "localhost"
port = 8080

[server.dev]
host = "localhost"
port = 8081

[database]
[database.test]
url = "postgres://localhost/mydb"
port = 15432

[database.dev]
url = "postgres://localhost/mydb"
port = 5432

test.json配置文件

{
    "debug": false,
    "fruits": ["apple", "banana", "cherry"],
    "server": {
        "test": {
            "host": "localhost",
            "port": 8080
        },
        "dev": {
            "host": "localhost",
            "port": 8081
        }
    },
    "database": {
        "test": {
            "url": "postgres://localhost/mydb",
            "port": 15432
        },
        "dev": {
            "url": "postgres://localhost/mydb",
            "port": 5432
        }
    }
}

读取配置文件

File::with_name()可以使用Path

use config::{Config, File};
use serde::Deserialize;

// server配置
#[derive(Debug, Deserialize)]
struct Server {
    test: ServerConfig,
    dev: ServerConfig,
}

#[derive(Debug, Deserialize)]
struct ServerConfig {
    host: String,
    port: u32,
}

// db配置
#[derive(Debug, Deserialize)]
struct Database {
    test: DatabaseConfig,
    dev: DatabaseConfig,
}

#[derive(Debug, Deserialize)]
struct DatabaseConfig {
    url: String,
    port: u32,
}


#[derive(Debug, Deserialize)]
struct Settings {
    debug: bool,
    fruits: Vec<String>,
    server: Server,
    database: Database,
}


fn main() -> Result<(), config::ConfigError> {
    let settings = Config::builder()
        .add_source(File::with_name("config/test"))
        .build()?
        .try_deserialize::<Settings>()?;

    println!("{:#?}", settings);
    Ok(())
}
Settings {
    debug: false,
    fruits: [
        "apple",
        "banana",
        "cherry",
    ],
    server: Server {
        test: ServerConfig {
            host: "localhost",
            port: 8080,
        },
        dev: ServerConfig {
            host: "localhost",
            port: 8081,
        },
    },
    database: Database {
        test: DatabaseConfig {
            url: "postgres://localhost/mydb",
            port: 15432,
        },
        dev: DatabaseConfig {
            url: "postgres://localhost/mydb",
            port: 5432,
        },
    },
}

Config::builder()用法

Config加载顺序

  • 整体
    • set_default(...) 最先加载
    • add_source(...) 中间按添加顺序覆盖
    • set_override(...) 最后加载,优先级最高
  • 多个相同的
    • 多个 add_source(...) 之间,顺序重要
    • 多个 set_default(...) 之间,如果设置同一路径,后面的会覆盖前面的
    • 多个 set_override(...) 之间,如果设置同一路径,后面的会覆盖前面的
let settings = Config::builder()
    .set_default("debug", false)?
    .add_source(File::with_name("config/default"))
    .add_source(File::with_name("config/development").required(false))
    .add_source(Environment::with_prefix("MYAPP").prefix_separator("_").separator("__"))
    .set_override("server.dev.port", 3000)?
    .build()?
    .try_deserialize::<Settings>()?;
默认值 < default.toml < development.toml < 环境变量 < set_override

设置默认值set_default

use config::Config;
use serde::Deserialize;

// server配置
#[derive(Debug, Deserialize)]
struct Server {
    test: ServerConfig,
    dev: ServerConfig,
}

#[derive(Debug, Deserialize)]
struct ServerConfig {
    host: String,
    port: u32,
}

#[derive(Debug, Deserialize)]
struct Settings {
    debug: bool,
    server: Server
}

fn main() -> Result<(), config::ConfigError> {
    let settings = Config::builder()
        // 设置默认值
        .set_default("debug", true)?
        .set_default("server.test.host", "127.0.0.1")?
        .set_default("server.test.port", 8080)?
        .set_default("server.dev.host", "0.0.0.0")?
        .set_default("server.dev.port", 9000)?
        .build()?
        .try_deserialize::<Settings>()?; // 转为结构体

    println!("{:#?}", settings);
    Ok(())
}
Settings {
    debug: true,
    server: Server {
        test: ServerConfig {
            host: "127.0.0.1",
            port: 8080,
        },
        dev: ServerConfig {
            host: "0.0.0.0",
            port: 9000,
        },
    },
}

加载配置add_source

配置文件导入

如果有相同配置,后面的导入会覆盖前面导入

  • File::with_name("config/server")
    • 表示读取 config/server.tomlconfig/server.jsonconfig/server.yaml 等配置文件
    • 不需要手写扩展名,config 这个库会根据支持的格式自动匹配
[server]

[server.dev]
host = "11.11.11.11"
port = 80
// 导入File
use config::{Config, File};
use serde::Deserialize;

// server配置
#[derive(Debug, Deserialize)]
struct Server {
    test: ServerConfig,
    dev: ServerConfig,
}

#[derive(Debug, Deserialize)]
struct ServerConfig {
    host: String,
    port: u32,
}

#[derive(Debug, Deserialize)]
struct Settings {
    debug: bool,
    server: Server,
}

fn main() -> Result<(), config::ConfigError> {
    let settings = Config::builder()
        .set_default("debug", true)?
        .set_default("server.test.host", "127.0.0.1")?
        .set_default("server.test.port", 8080)?
        .set_default("server.dev.host", "0.0.0.0")?
        .set_default("server.dev.port", 9000)?
        // 从配置文件导入
        .add_source(File::with_name("config/server").required(false))
        .build()?
        .try_deserialize::<Settings>()?; // 转为结构体

    println!("{:#?}", settings);
    Ok(())
}
Settings {
    debug: true,
    server: Server {
        test: ServerConfig {
            host: "127.0.0.1",
            port: 8080,
        },
        dev: ServerConfig {
            host: "11.11.11.11",
            port: 80,
        },
    },
}
读取多个配置文件
  • .required(false) 表示配置文件不存在也不会报错,适合可选配置文件,例如本地开发配置、环境专用配置。
config/
    default.toml
    development.toml
let settings = Config::builder()
    .add_source(File::with_name("config/default"))
    .add_source(File::with_name("config/development").required(false))
    .build()?
    .try_deserialize::<Settings>()?;

环境变量获取

⚠️如果不显式设置prefix_separator("_"),那么prefix和字段之间默认也会使用separator("__")

  • prefix_separator决定 MYAPP 和后面配置名之间怎么分开

  • separator决定后面配置名内部的嵌套层级怎么分开

  • Environment::with_prefix("MYAPP").separator("__")

    • MYAPP__SERVER__DEV__PORT
      • MYAPP__表示“这是我的应用配置”
      • SERVER__DEV__PORT表示嵌套字段server.dev.port
  • Environment::with_prefix("MYAPP").prefix_separator("_").separator("__")

    • MYAPP_SERVER__DEV__PORT
      • MYAPP_表示“这是我的应用配置”
      • SERVER__DEV__PORT表示嵌套字段server.dev.port
use config::{Config, Environment, File};
use serde::Deserialize;

// server配置
#[derive(Debug, Deserialize)]
struct Server {
    test: ServerConfig,
    dev: ServerConfig,
}

#[derive(Debug, Deserialize)]
struct ServerConfig {
    host: String,
    port: u32,
}

#[derive(Debug, Deserialize)]
struct Settings {
    debug: bool,
    server: Server,
}

fn main() -> Result<(), config::ConfigError> {
    let settings = Config::builder()
        .set_default("debug", true)?
        .set_default("server.test.host", "127.0.0.1")?
        .set_default("server.test.port", 8080)?
        .set_default("server.dev.host", "0.0.0.0")?
        .set_default("server.dev.port", 9000)?
        .add_source(File::with_name("config/server").required(false))
        .add_source(Environment::with_prefix("MYAPP").prefix_separator("_").separator("__"))
        .build()?
        .try_deserialize::<Settings>()?; // 转为结构体

    println!("{:#?}", settings);
    Ok(())
}
MYAPP_SERVER__DEV__PORT=2000 cargo run

Settings {
    debug: true,
    server: Server {
        test: ServerConfig {
            host: "127.0.0.1",
            port: 8080,
        },
        dev: ServerConfig {
            host: "11.11.11.11",
            port: 2000,
        },
    },
}

set_override

代码里最后拍板,优先级最高

  • 用于myapp run --port 3000直接覆盖
use config::{Config, Environment, File};
use serde::Deserialize;

// server配置
#[derive(Debug, Deserialize)]
struct Server {
    test: ServerConfig,
    dev: ServerConfig,
}

#[derive(Debug, Deserialize)]
struct ServerConfig {
    host: String,
    port: u32,
}

#[derive(Debug, Deserialize)]
struct Settings {
    debug: bool,
    server: Server,
}

fn main() -> Result<(), config::ConfigError> {
    let mut config_build = Config::builder()
        .set_default("debug", true)?
        .set_default("server.test.host", "127.0.0.1")?
        .set_default("server.test.port", 8080)?
        .set_default("server.dev.host", "0.0.0.0")?
        .set_default("server.dev.port", 9000)?
        .add_source(File::with_name("config/server").required(false))
        .add_source(Environment::with_prefix("MYAPP").prefix_separator("_").separator("__"));

    // 添加识别--port
    let args: Vec<String> = std::env::args().collect();

    let mut i = 0;
    while i < args.len() {
        if args[i] == "--port" && i + 1 < args.len() {
            if let Ok(port) = args[i + 1].parse::<u32>() {
                config_build= config_build.set_override("server.dev.port", port)?;
            }
            i += 1;
        }
        i += 1;
    }

    let settings = config_build
        .build()?
        .try_deserialize::<Settings>()?; // 转为结构题

    println!("{:#?}", settings);
    Ok(())
}
cargo run -- --port 1234

Settings {
    debug: true,
    server: Server {
        test: ServerConfig {
            host: "127.0.0.1",
            port: 8080,
        },
        dev: ServerConfig {
            host: "11.11.11.11",
            port: 1234,
        },
    },
}
posted @ 2026-08-10 10:07  lxd670  阅读(4)  评论(0)    收藏  举报