自定义UnmarshalYAML,如何在自定义类型上实现Unmarshaler接口

时间:2018-03-28 09:08:12

标签: go yaml unmarshalling custom-type

我解析.yaml文件,需要以自定义方式解组其中一个属性。我正在使用"gopkg.in/yaml.v2"包。

有问题的属性在我的.yaml文件中存储如下:

endPointNumberSequences:
  AD1: [ 0, 10, 14, 1, 11, 2, 100, 101, 12 ]

所以它基本上是一种map[string][]uint16类型 但我需要map[string]EpnSeq,其中EpnSeq定义为:
type EpnSeq map[uint16]uint16

我的结构:

type CitConfig struct {
    // lots of other properties
    // ...

    EndPointNumberSequences  map[string]EpnSeq `yaml:"endPointNumberSequences"`
}

我尝试在其上实现Unmarshaler接口:

// Implements the Unmarshaler interface of the yaml pkg.
func (e EpnSeq) UnmarshalYAML(unmarshal func(interface{}) error) error {
    yamlEpnSequence := make([]uint16, 0)
    err := unmarshal(&yamlEpnSequence)
    if err != nil {
        return err
    }

    for priority, epn := range yamlEpnSequence {
        e[epn] = uint16(priority) // crashes with nil pointer
    }

    return nil
}

我的问题是UnmarshalYAML函数内部没有定义EpnSeq类型,导致运行时出现nil指针异常。
我如何在这里正确实现Unmarshaler接口?

1 个答案:

答案 0 :(得分:2)

由于@Volker没有发表评论作为回答,我会为了完整起见而这样做 所以我已经在正确的道路上了,但在初始化它时,根本没有取消引用我的struct的指针接收器:

// Implements the Unmarshaler interface of the yaml pkg.
func (e *EpnSeq) UnmarshalYAML(unmarshal func(interface{}) error) error {
    yamlEpnSequence := make([]uint16, 0)
    err := unmarshal(&yamlEpnSequence)
    if err != nil {
        return err
    }

    // make sure to dereference before assignment, 
    // otherwise only the local variable will be overwritten
    // and not the value the pointer actually points to
    *e = make(EpnSeq, len(yamlEpnSequence))
    for priority, epn := range yamlEpnSequence {
        e[epn] = uint16(priority) // no crash anymore
    }

    return nil
}