Unmarshal a YAML to a struct with unexpected fields in Go

岁酱吖の 提交于 2020-01-15 12:11:23

问题


I encountered an issue while trying to unmarshal a struct with an unexported field using github.com/go-yaml/yaml. The struct looks like:

type Example struct {
    ExportedField   string                     `yaml:"exported-field"`
    OneMoreExported string                     `yaml:"one-more-exported"`
    unexportedField map[string]*AnotherExample `yaml:"unexported-field"`
}

type AnotherExample struct {
    Name string `yaml:"name"`
}

And I'd like to unmarshal such YAML as

exported-field: lorem ipsum
one-more-exported: dolor set
unexported-field:
  something:
    name: anything

What I tried is a custom unmarshaler:

func (example *Example) UnmarshalYAML(unmarshal func(interface{}) error) error {
    type Alias Example
    tmp := struct {
        UnexportedField map[string]*AnotherExample `yaml:"unexported-field"`
        *Alias
    }{
        Alias: (*Alias)(example),
    }
    if err := unmarshal(&tmp); err != nil {
        return err
    }
    if tmp.UnexportedField != nil {
        example.unexportedField = tmp.UnexportedField
    }
    example.CopyJobNonNil(Example(*tmp.Alias)) // Copies all the non-nil fields from the passed Example instance

    return nil
}

tmp after calling unmarshal() doesn't contain any fields but unexportedField — other fields seems to be omitted.

The reproduced issue on Go Playground (although it isn't working due to the dependencies): https://play.golang.org/p/XZg7tEPGXna


回答1:


Because most Go unmarshalling packages (including the encoding/* packages) use the reflect package to get at struct fields, and reflect can't access unexported struct fields, the unmarshaler can't parse into unexported fields.

That said, there is still a way to do it. You can unmarshall the YAML into an an unexported type with public fields, which can then be embedded into an exported type. Getters and setters in the same package can just use the embedded struct.

For example:

// Define the types...

type innerData struct {
    ExportedField string
    unexportedField string
}

type Data struct {
    innerData
}


// and then...

d := Data{}
DoSomeUnmarshalling(yamlbytes, &d.innerData)


// and then you can use getters/setters/whatever on `Data`

func (d *Data) GetUnexported() string {
    return d.innerData.unexportedField;
}

(warning: completely untested)

See JSON and dealing with unexported fields for reference.



来源:https://stackoverflow.com/questions/48674624/unmarshal-a-yaml-to-a-struct-with-unexpected-fields-in-go

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!