You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GoLang读取YAML文件对象数组遇Unmarshal错误求助

解决Go解析YAML对象数组的错误

问题分析

错误cannot unmarshal !!map into []config.Document的核心原因有三点:

  • Go结构体的私有字段(首字母小写)无法被yaml包访问
  • Unmarshal目标类型不匹配:试图将顶层为map结构的YAML数据直接解析到切片类型的c.docs
  • YAML结构与Go结构体的映射关系不匹配

具体修复步骤

1. 导出结构体字段

Go中只有首字母大写的字段才能被外部包(如yaml.v3)序列化/反序列化,修改结构体定义:

type DocumentationInfo struct {
    Docs []Document `yaml:"document"` // 首字母大写导出,yaml标签匹配YAML中的document键
}

type Document struct {
    Title    string `yaml:"title"`    // 首字母大写
    FileName string `yaml:"filename"` // 首字母大写,匹配YAML中的filename键(注意小写)
}

2. 修正Unmarshal的目标对象

原代码直接将YAML解析到切片c.docs,但YAML顶层是包含DocumentationInfo键的map,应改为解析到整个DocumentationInfo结构体实例:

// 错误写法:err = yaml.Unmarshal(yamlFile, c.docs)
err = yaml.Unmarshal(yamlFile, c) // 改为解析到结构体实例c

3. 调整YAML结构(或结构体标签)

原YAML顶层键为DocumentationInfo,与结构体映射不匹配,推荐选择更简洁的方案A:

选项A:修改YAML文件,去掉顶层的DocumentationInfo键

调整后的YAML内容:

document:
  - {fileName: "foo.md", title: "I am an foo title"}
  - {fileName: "test.md", title: "I am an test title"}
  - {fileName: "bar.md", title: "I am an bar title"}
  - {fileName: "nice.md", title: "I am an nice title"}

选项B(可选):新增顶层结构体匹配YAML结构

如果不想修改YAML,可新增一个顶层结构体:

type RootConfig struct {
    DocInfo DocumentationInfo `yaml:"DocumentationInfo"`
}

然后在Init方法中解析:

var root RootConfig
err = yaml.Unmarshal(yamlFile, &root)
if err != nil {
    log.Fatalf("Unmarshal: %v", err)
}
c.Docs = root.DocInfo.Docs

4. 修正遍历逻辑

字段导出后,遍历需使用大写的字段名:

for _, doc := range c.Docs {
    docInfo[doc.FileName] = doc
}

完整修复后的代码示例

package config

import (
    "gopkg.in/yaml.v3"
    "log"
    "os"
    "path/filepath"
    "runtime"
)

type DocumentationInfo struct {
    Docs []Document `yaml:"document"`
}

type Document struct {
    Title    string `yaml:"title"`
    FileName string `yaml:"filename"`
}

func (c *DocumentationInfo) Init() map[string]Document {
    _, b, _, _ := runtime.Caller(0)
    basepath := filepath.Dir(b)

    yamlFile, err := os.ReadFile(basepath + "/documentation.yaml")
    if err != nil {
        log.Printf("yamlFile.Get err   #%v ", err)
    }
    err = yaml.Unmarshal(yamlFile, c)
    if err != nil {
        log.Fatalf("Unmarshal: %v", err)
    }

    docInfo := make(map[string]Document)

    for _, doc := range c.Docs {
        docInfo[doc.FileName] = doc
    }

    return docInfo
}

func NewDocumentConfig() *DocumentationInfo {
    return &DocumentationInfo{}
}

对应的YAML文件(选项A):

document:
  - {fileName: "foo.md", title: "I am an foo title"}
  - {fileName: "test.md", title: "I am an test title"}
  - {fileName: "bar.md", title: "I am an bar title"}
  - {fileName: "nice.md", title: "I am an nice title"}

内容的提问来源于stack exchange,提问作者Mike3355

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 23:13:29