Golang中UnmarshalYAML未被调用的问题如何解决
Golang中UnmarshalYAML未被调用的问题如何解决
序列化一个包含 Wrapper 结构体字段的结构体 C 时,该 Wrapper 实现了 MarshalYAML 方法,但该方法未被调用。
这是一个错误,还是我哪里做错了?
package ci
import (
"errors"
"fmt"
"testing"
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v3"
)
type Interface interface {
DoUnmarshal(v *yaml.Node) error
}
type Impl struct {
A string `yaml:"aa"`
}
func (s *Impl) DoUnmarshal(v *yaml.Node) error {
return v.Decode(&s)
}
type MyType struct {
Value bool `yaml:"v"`
Custom Wrapper `yaml:"custom"`
}
type Wrapper struct {
inst Interface
}
var called bool
func (w *Wrapper) MarshalYAML() (interface{}, error) {
fmt.Printf("Marshal wrapper.")
called = true
return w.inst, nil
}
func (w *Wrapper) UnmarshalYAML(v *yaml.Node) error {
fmt.Printf("Unmarshal wrapper.")
return w.inst.DoUnmarshal(v)
}
func TestUnmarshal(t *testing.T) {
c := MyType{
Value: true,
Custom: Wrapper{inst: &Impl{A: "asdf"}}}
b, e := yaml.Marshal(&c)
require.NoError(t, e)
t.Logf("\n%v", string(b))
require.True(t, called, "MarshalYAML is not called.")
}
更多关于Golang中UnmarshalYAML未被调用的问题如何解决的实战教程也可以访问 https://www.itying.com/category-94-b0.html
type MyType struct {
Value bool `yaml:"v"`
Custom *Wrapper `yaml:"custom"`
}
func TestUnmarshal(t *testing.T) {
c := MyType{
Value: true,
Custom: &Wrapper{inst: &Impl{A: "asdf"}},
}
更多关于Golang中UnmarshalYAML未被调用的问题如何解决的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
补充一下@peakedshout提到的内容:你满足的是指针接收器的接口,而不是值接收器的接口。看看这个StackOverflow上的问题:
Custom MarshalJSON() never gets called in Go
标签 json, go, marshalling
提问者 Anders Sjöqvist 于 08:26PM - 27 Jan 14 UTC
这个问题是关于 MarshalJSON 的,但同样的道理也适用。
在Go的yaml.v3包中,MarshalYAML()方法需要满足特定的签名要求才能被正确调用。根据你的代码,问题在于MarshalYAML()方法应该返回(interface{}, error),但yaml.v3包实际上期望的是MarshalYAML() (*yaml.Node, error)签名。
以下是修正后的代码示例:
package ci
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v3"
)
type Interface interface {
DoUnmarshal(v *yaml.Node) error
}
type Impl struct {
A string `yaml:"aa"`
}
func (s *Impl) DoUnmarshal(v *yaml.Node) error {
return v.Decode(&s)
}
type MyType struct {
Value bool `yaml:"v"`
Custom Wrapper `yaml:"custom"`
}
type Wrapper struct {
inst Interface
}
var called bool
func (w *Wrapper) MarshalYAML() (interface{}, error) {
fmt.Printf("Marshal wrapper.")
called = true
// 对于yaml.v3,需要返回*yaml.Node
node := &yaml.Node{}
err := node.Encode(w.inst)
return node, err
}
func (w *Wrapper) UnmarshalYAML(v *yaml.Node) error {
fmt.Printf("Unmarshal wrapper.")
return w.inst.DoUnmarshal(v)
}
func TestUnmarshal(t *testing.T) {
c := MyType{
Value: true,
Custom: Wrapper{inst: &Impl{A: "asdf"}}}
b, e := yaml.Marshal(&c)
require.NoError(t, e)
t.Logf("\n%v", string(b))
require.True(t, called, "MarshalYAML is not called.")
}
如果你使用的是yaml.v2版本,MarshalYAML()方法签名可以是(interface{}, error)。但对于yaml.v3,需要调整为返回(*yaml.Node, error):
func (w *Wrapper) MarshalYAML() (*yaml.Node, error) {
fmt.Printf("Marshal wrapper.")
called = true
node := &yaml.Node{}
err := node.Encode(w.inst)
return node, err
}
另外,确保UnmarshalYAML方法在反序列化时被正确调用,需要验证yaml数据是否包含custom字段。测试示例如下:
func TestUnmarshalYAML(t *testing.T) {
yamlData := `v: true
custom:
aa: "test"`
var result MyType
result.Custom = Wrapper{inst: &Impl{}}
err := yaml.Unmarshal([]byte(yamlData), &result)
require.NoError(t, err)
require.Equal(t, "test", result.Custom.inst.(*Impl).A)
}

