问题
I parse a .yaml file and need to unmarshal one of its properties in a custom manner. I am using the "gopkg.in/yaml.v2"
package.
The property in question is stored like this in my .yaml file:
endPointNumberSequences:
AD1: [ 0, 10, 14, 1, 11, 2, 100, 101, 12 ]
So it is basically a map[string][]uint16
kind of type.
But I need map[string]EpnSeq
where EpnSeq
is defined as:type EpnSeq map[uint16]uint16
My struct:
type CitConfig struct {
// lots of other properties
// ...
EndPointNumberSequences map[string]EpnSeq `yaml:"endPointNumberSequences"`
}
I tried to implement the Unmarshaler interface on it like this:
// 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
}
My problem is that inside the UnmarshalYAML
function the EpnSeq
type is not defined, causing a nil pointer exception at runtime.
How do I correctly implement the Unmarshaler interface here?
回答1:
Since @Volker did not post his comment as answer, I will do for the sake of completeness.
So I was already on the right path, but simply failed to dereference the pointer receiver of my struct, when initializing it:
// 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
}
来源:https://stackoverflow.com/questions/49530395/custom-unmarshalyaml-how-to-implement-unmarshaler-interface-on-custom-type