一个编译期读取配置的过程宏(proc-macro)。dot!("KEY") 在编译时从 .env 文件
或系统环境变量中取出值,并把它作为 &'static str 字面量内联进二进制——运行时没有任何
文件读取或解析开销,缺值则编译报错(而非运行时 panic)。
# Cargo.toml
[dependencies]
sdot = { path = "./sdot" }// 取值;编译期找不到则编译失败,用默认错误信息
let api_key: &str = sdot::dot!("API_KEY");
// 第二个参数自定义“找不到”时的编译错误信息
let api_key: &str = sdot::dot!("API_KEY", "请在 .env 里配置 API_KEY");宏接受 1~2 个字符串字面量参数。传入非字面量(如 dot!(FOO))会得到指向出错位置的
编译错误,而不是宏 panic。
按以下顺序解析,先命中者胜:
.env文件:从CARGO_MANIFEST_DIR开始逐级向上查找配置文件。- 系统环境变量:
std::env::var(KEY)(编译时所在进程的环境)。
两者都没有,则产生编译错误。文件是可选的——没有任何 .env.* 文件时,仅靠系统环境变量
也能工作。
根据编译模式选择文件名:
| 编译模式 | 文件名 |
|---|---|
| debug(默认) | .env.dev |
| release | .env.prod |
⚠️ 该选择基于dot这个 proc-macro crate 自身编译时的debug_assertions。通常cargo build与cargo build --release会让它跟随切换,但debug-assertions是可被独立配置的 ([profile.release] debug-assertions = true、build-override、自定义--profile), 此时文件可能选错。需要稳健切换时,建议改用 cargo feature 或显式环境变量。
# 以 # 开头的整行是注释
API_KEY=abc123
DATABASE_URL="postgres://localhost/db" # 值两侧的成对引号会被去掉
PORT=8080KEY=VALUE,按第一个=分割;空行与#开头的行忽略。- 值会
trim,并去掉首尾的"或'。 - 不支持行内注释(
KEY=val # 注释中的# 注释会算进值里)、转义、多行值。
- 值会被写进二进制:
dot!把配置值固化成字符串字面量编译进产物。不要用它嵌入生产密钥 (二进制可被strings提取),且改配置需要重新编译。 - 文件变更会触发重编译:取值成功且存在
.env.*文件时,宏会发出include_bytes!(<env 文件>),使 rustc 追踪该文件,文件内容变化即重新编译。 - 系统环境变量变更不触发重编译:
std::env::var在 proc-macro 中不会被 rustc 登记为 重编译依赖。改了环境变量但源码/文件未变时可能不会重新编译,必要时执行cargo clean。
仓库用 trybuild 固化编译期行为(tests/ui/):
cargo test # 运行通过/失败用例
TRYBUILD=overwrite cargo test # syn 版本或错误信息变动后,重新生成 .stderr 快照