我正在玩 golang yaml v3 库。目标是从带有注释的文件中解析任何 yaml(这意味着我没有预定义的结构),能够在结果树中设置或取消设置任何值并将其写回文件。


但是,我遇到了相当奇怪的行为。正如您在下面的代码中看到的,如果传递给 Unmarshal 函数的主要类型是interface{},则不会保留任何注释,并且库使用映射和切片来表示 yaml 的结构。另一方面,如果我使用(在这种情况下)[]yaml.Node结构,它确实在内部将所有节点表示为yaml.Nodeor []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))


}