config — 配置加载

这个示例把 pkg/core/config 的全部规则压在一个可运行的程序里: 结构体 tag 提供默认值、环境变量覆盖与可选键,YAML 里的 ${VAR} 在解析前展开。 看完你会知道一个配置段该怎么写,以及缺键时程序会在什么时候、以什么方式失败。

运行

go run ./examples/config

# 环境变量优先于文件:
DB_DSN='postgres://localhost/overridden' go run ./examples/config

没有外部依赖,不需要 make dev,也不监听端口——它是纯库演示。 -conf 默认指向 examples/config/config.yaml, 所以从仓库根目录直接跑就能读到那份文件。

它演示了什么

tag 是怎么写的

下面这段来自 examples/config/main.go 的 Config 定义。 注意 MaxIdleConns 是 optional——文件里故意没有这个键, 读出来就是零值;而 DSN 没有默认值,只能靠文件或 DB_DSN 提供。

type Config struct {
	HTTP struct {
		Addr    string        `json:"addr" default:":8080"`
		Timeout time.Duration `json:"timeout" default:"10s"`
	} `json:"http"`

	DB struct {
		DSN          string `json:"dsn" env:"DB_DSN"` // env 优先于文件
		MaxOpenConns int    `json:"max_open_conns" default:"16"`
		MaxIdleConns int    `json:"max_idle_conns" optional:""` // 可缺省 → 零值
	} `json:"db"`

	Features []string `json:"features" default:"a,b"` // "a,b" 或 YAML 列表
	Debug    bool     `json:"debug" default:"false"`
}

缺键就该在启动时炸

示例最后用一段最小的结构体证明这件事:没有 default 也没有 optional 的 key 缺失时,config.Parse 直接返回错误。 这来自 examples/config/main.go 的末尾几行。

// 没有 default 也没有 optional 的 key 缺失时会报错——配置错误在启动
// 时就该炸,而不是等到运行时才 nil panic。
var strict struct {
	Required string `json:"required"`
}
err := config.Parse([]byte("other: 1"), &strict)
fmt.Printf("\n缺少必填 key:%v\n", err)

验证

程序不提供 HTTP 接口,直接看标准输出。默认跑(读 config.yaml):

go run ./examples/config
conf      = examples/config/config.yaml
http      = 0.0.0.0:8080 (timeout 5s)
db        = file:examples-config.db (max_open=8 max_idle=0)
features  = [cache events]
debug     = true

缺少必填 key:config: missing key "required"
inline    = from-bytes

其中 timeout 5s、max_open=8、[cache events]、 debug = true 全部来自 config.yaml; max_idle=0 是因为文件里没有该键而字段标了 optional。 加环境变量后 db 行会换掉:

DB_DSN='postgres://localhost/overridden' go run ./examples/config
# db        = postgres://localhost/overridden (max_open=8 max_idle=0)
flowchart TD
    A["YAML 文本
${VAR} / ${VAR:default}"] --> B["环境变量展开"] B --> C["按 json tag
定位结构体字段"] C --> D{"key 在文件里吗?"} D -- 在 --> E["用文件值"] D -- 不在 --> F{"有 env: tag?"} F -- "环境变量存在" --> G["用环境变量值"] F -- "否则" --> H{"有 default: tag?"} H -- 有 --> I["用默认值"] H -- 无 --> J{"optional?"} J -- "是" --> K["留零值"] J -- "否" --> L["返回错误
启动失败"] classDef bad fill:#fdf0f0,stroke:#a33,color:#2b2722 class L bad
一个键的取值路径。唯一会中止启动的分支是最后一格:既没有值可选, 也没被标记为可缺省。

测试

main_test.go 把 tag 语义当成接口来钉。它断言的具体事实:

go test ./examples/config

相关

配置概念页 tag 语义、必需段与热更的完整规则。 AI Skills 让 AI 按规范把配置接进你的项目。 示例索引 全部 20 个可运行示例。

相关示例