
在 go 中使用 yaml.v2 解析含多个同类结构的 yaml 数据时,需将 yaml 组织为列表格式,并反序列化为结构体切片,而非单个结构体,从而一次性获取全部实例。
YAML 本身不支持同一层级下重复键(如连续出现两个 first:),因此原始示例中看似“两组配置”的 YAML 实际被解析器视为键冲突——后出现的值覆盖前值,最终只保留最后一组数据。这是 YAML 规范决定的行为,不是 go 或 yaml.v2 的限制,而是数据格式问题。
✅ 正确做法是:将多组结构显式表达为 YAML 序列(即 YAML List / Array),对应 Go 中的切片([]Container):
- first: first value second: nested1: GET nested2: /bin/bash nested3: /usr/local/bin/customscript nested4: 8080 - first: second value second: nested1: POST nested2: /bin/ksh nested3: /usr/local/bin/customscript2 nested4: 8081
对应 Go 代码只需修改目标变量类型与解包逻辑:
package main import ( "fmt" "gopkg.in/yaml.v2" "log" ) type Container struct { First string `yaml:"first"` Second struct { Nested1 string `yaml:"nested1"` Nested2 string `yaml:"nested2"` Nested3 string `yaml:"nested3"` Nested4 int `yaml:"nested4"` } `yaml:"second"` } var data = ` - first: first value second: nested1: GET nested2: /bin/bash nested3: /usr/local/bin/customscript nested4: 8080 - first: second value second: nested1: POST nested2: /bin/ksh nested3: /usr/local/bin/customscript2 nested4: 8081 ` func main() { var containers []Container // ← 关键:声明为切片 err := yaml.Unmarshal([]byte(data), &containers) if err != nil { log.Fatalf("YAML unmarshal error: %v", err) } fmt.Printf("---%d container(s) found:n", len(containers)) for i, c := range containers { fmt.Printf("[%d] %+vn", i+1, c) } }
? 注意事项:
立即学习“go语言免费学习笔记(深入)”;
- 字段标签不可省略:YAML 键名默认区分大小写且不自动匹配驼峰,务必通过 `yaml:”keyname”` 显式绑定(如 First → “first”);
- 嵌套结构也需标签:内层匿名结构体的字段同样需要 yaml: 标签,否则无法正确映射;
- 避免重复键陷阱:不要依赖“多个同级键”实现多实例——YAML 解析器会静默覆盖,应始终使用 – 列表语法;
- 错误处理建议:生产环境推荐配合 yaml.UnmarshalStrict(需升级至 gopkg.in/yaml.v3)防止未知字段被忽略。
? 扩展提示:若 YAML 源无法修改(如第三方固定格式),可先用正则或 yaml.node 手动分块解析,但代价较高;优先推动 YAML 格式标准化为数组形式,更符合 Go 的类型安全与工程实践。