一尘不染

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

go

我解析了.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接口?


阅读 807

收藏
2020-07-02

共1个答案

一尘不染

由于@Volker并未发布他的评论作为答案,因此我会为了完整性而这样做。
所以我已经走在正确的道路上,但是在初始化它时却无法取消引用我的结构的指针接收器:

// 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
}
2020-07-02