如何接收未知结构体并反序列化YAML后返回该结构体?
问题解答
1. 是否可行?
完全可行。Go的反射机制配合gopkg.in/yaml.v2或gopkg.in/yaml.v3包的反序列化能力,支持动态传入任意结构体指针和YAML文件,完成数据填充。
2. 如何实现?
你的代码存在两个核心问题,修正后即可正常工作:
问题点分析
- 结构体字段可见性:Go中只有首字母大写的字段是导出的,
yaml包依赖反射访问字段,小写字段无法被外部包修改,导致数据无法填充。 - Unmarshal参数错误:你传入的
myStructure已经是结构体指针(main中用new(MyStruct)创建的*MyStruct),但函数里又传递了&myStructure(即**interface{}类型),这会让yaml.Unmarshal把数据写入临时创建的新对象,而非你传入的原结构体指针。
修正后的代码
YAML文件内容(heresmyyaml.yaml)
name: "Jim" age: 39 pets: - "Snake" - "Dog"
Go代码
package main import ( "fmt" "os" "gopkg.in/yaml.v3" ) // 修正字段首字母为大写,确保yaml包能访问 type MyStruct struct { Name string `yaml:"name"` Age int `yaml:"age"` Pets []string `yaml:"pets"` // 可以添加任意多其他大写字段 } // ReadMyStruct 接收YAML文件路径和结构体指针,填充数据后返回原指针(或直接修改传入的指针) func ReadMyStruct(yamlFile string, myStructure interface{}) error { fh, err := os.ReadFile(yamlFile) if err != nil { return err } // 直接传入myStructure(已经是指针),不需要取地址 if err := yaml.Unmarshal(fh, myStructure); err != nil { return err } return nil } func main() { myStruct := new(MyStruct) // 调用函数,传入结构体指针 err := ReadMyStruct("heresmyyaml.yaml", myStruct) if err != nil { fmt.Printf("Error: %v\n", err) return } // 直接访问原结构体的字段即可 fmt.Println("Name:", myStruct.Name) fmt.Println("Age:", myStruct.Age) fmt.Println("Pets:", myStruct.Pets) // 如果需要返回值形式,也可以修改函数返回interface{},但需要类型断言 // returned, err := ReadMyStructWithReturn("heresmyyaml.yaml", myStruct) // if err != nil { ... } // rs := returned.(*MyStruct) // fmt.Println(rs.Name) }
关键说明
- 必须传入结构体指针给
ReadMyStruct,这样yaml.Unmarshal才能直接修改指针指向的实例数据。 - 结构体字段必须首字母大写,并通过
yaml:"tag"指定YAML中的键名。 - 如果函数需要返回填充后的实例,直接返回传入的
myStructure即可,后续使用时通过类型断言转换为具体的结构体类型(如returned.(*MyStruct))。
运行输出
Name: Jim Age: 39 Pets: [Snake Dog]
内容的提问来源于stack exchange,提问作者user16545584
相关产品推荐
相关产品推荐

