Golang中结构体内部类型别名YAML反序列化失败问题排查
问题:YAML反序列化后Kind字段值未正确更新
问题场景
需要将以下YAML内容反序列化到Resource结构体:
kind: bar name: baryaml
Resource及相关类型定义如下:
type Kind int const ( KIND_FOO Kind = iota KIND_BAR ) type Resource struct { Kind Kind Name string }
已实现Kind类型的UnmarshalYAML方法,控制台输出显示已解析出正确的Kind值(1),但最终Resource实例的Kind字段仍为初始值0,与预期不符:
当前输出:
# Output: Unmarshaled kind: 1 yamlBar: {0 baryaml}
预期输出:
# Expected Output: Unmarshaled kind: 1 yamlBar: {1 baryaml}
相关完整代码:
package main import ( "fmt" "gopkg.in/yaml.v3" ) type Kind int const ( KIND_FOO Kind = iota KIND_BAR ) func (k *Kind) UnmarshalYAML(value *yaml.Node) error { var kind string err := value.Decode(&kind) if err != nil { return err } var x Kind switch kind { case "foo": x = KIND_FOO case "bar": x = KIND_BAR default: return fmt.Errorf("unknown kind: %s", kind) } k = &x fmt.Println("Unmarshaled kind:", *k) return nil } type Resource struct { Kind Kind Name string } func main() { var yamlBar = ` kind: bar name: baryaml ` r := Resource{} err := yaml.Unmarshal([]byte(yamlBar), &r) if err != nil { panic(err) } fmt.Println("yamlBar:", r) }
问题原因
问题出在UnmarshalYAML方法中的k = &x这行代码。
在Go语言中,指针类型的方法接收者是值传递的——方法内部的k是原接收者指针的副本。当你执行k = &x时,只是修改了这个副本的指向,让它指向局部变量x的地址,但完全没有修改原Resource结构体中Kind字段的内存值。原结构体的Kind字段始终是初始值0,自然不会被更新。
修复方法
不要重新给接收者指针赋值,而是直接修改指针指向的内存内容,将k = &x替换为*k = x:
修改后的UnmarshalYAML方法:
func (k *Kind) UnmarshalYAML(value *yaml.Node) error { var kind string err := value.Decode(&kind) if err != nil { return err } var x Kind switch kind { case "foo": x = KIND_FOO case "bar": x = KIND_BAR default: return fmt.Errorf("unknown kind: %s", kind) } *k = x // 直接修改指针指向的内存值 fmt.Println("Unmarshaled kind:", *k) return nil }
这样修改后,解析得到的x值会直接写入到Resource结构体Kind字段的内存地址中,最终就能得到符合预期的结果。
内容的提问来源于stack exchange,提问作者C. Falsaperla
相关产品推荐
相关产品推荐

