【发布时间】:2020-09-15 15:04:46
【问题描述】:
我正在使用 golang yaml v3 库。目标是使用 cmets 从文件中解析任何 yaml(这意味着我没有预定义的结构),能够设置或取消设置结果树中的任何值并将其写回文件。
但是,我遇到了相当奇怪的行为。正如您在下面的代码中看到的,如果传递给 Unmarshal 函数的主要类型是 interface{},则不保留任何 cmets,并且库使用映射和切片来表示 yaml 的结构。另一方面,如果我使用(在这种情况下)[]yaml.Node 结构,它会在内部将所有节点表示为yaml.Node 或[]yaml.Node。这或多或少是我想要的,因为它允许保留评论。但是,这不是一个通用的解决方案,因为至少有两种不同的场景 - YAML 以数组或地图开头,我不确定如何优雅地处理这两种情况。
您能否指出我正确的方向并详细说明图书馆为什么会这样?
package main
import (
"fmt"
"reflect"
"gopkg.in/yaml.v3"
)
type Document interface{} // change this to []yaml.Node and it will work with comments // change it to yaml.Node and it will not work
var data string = ` # Employee records
- martin:
name: Martin D'vloper
job: Developer
skills:
- python
- perl
- pascal
- tabitha:
name: Tabitha Bitumen
job: Developer
skills:
- lisp
- fortran
- erlang
`
func toSlice(slice interface{}) []interface{} {
s := reflect.ValueOf(slice)
if s.Kind() != reflect.Slice {
panic("InterfaceSlice() given a non-slice type")
}
ret := make([]interface{}, s.Len())
for i:=0; i<s.Len(); i++ {
ret[i] = s.Index(i).Interface()
}
return ret
}
func main() {
var d Document
err := yaml.Unmarshal([]byte(data), &d)
if err != nil {
panic(err)
}
slice := toSlice(d)
fmt.Println(reflect.ValueOf(slice[0]).Kind())
fmt.Println(reflect.TypeOf(d))
fmt.Println(reflect.ValueOf(d).Kind())
output, err := yaml.Marshal(&d)
if err != nil {
panic(err)
}
fmt.Println(string(output))
}
【问题讨论】: