golang:解组动态YAML通告

xqkwcwgp  于 2023-03-21  发布在  Go
关注(0)|答案(1)|浏览(156)

我想动态更改struct的注解,并使用yaml.Unmarshal,如下所示:

  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. "gopkg.in/yaml.v3"
  6. )
  7. type User struct {
  8. Name string `yaml:"dummy"`
  9. }
  10. func (u *User) UnmarshalYAML(node *yaml.Node) error {
  11. value := reflect.ValueOf(*u)
  12. t := value.Type()
  13. fields := make([]reflect.StructField, 0)
  14. for i := 0; i < t.NumField(); i++ {
  15. fields = append(fields, t.Field(i))
  16. if t.Field(i).Name == "Name" {
  17. fields[i].Tag = `yaml:"name"` // Dynamic annotation
  18. }
  19. }
  20. newType := reflect.StructOf(fields)
  21. newValue := value.Convert(newType)
  22. err := node.Decode(newValue.Interface()) // Cause error because it's not pointer
  23. return err
  24. }
  25. var dat string = `name: abc`
  26. func main() {
  27. out := User{}
  28. yaml.Unmarshal([]byte(dat), &out)
  29. fmt.Printf("%+v\n", out)
  30. }

它会导致panic: reflect: reflect.Value.Set using unaddressable value [recovered]这样的错误,我想这是因为node.Decode没有和指针一起使用。那么如何创建新类型的指针呢?

3wabscal

3wabscal1#

下面是更新后的演示:

  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. "unsafe"
  6. "gopkg.in/yaml.v3"
  7. )
  8. type User struct {
  9. Name string `yaml:"dummy"`
  10. }
  11. func (u *User) UnmarshalYAML(node *yaml.Node) error {
  12. t := reflect.TypeOf(*u)
  13. fields := make([]reflect.StructField, 0)
  14. for i := 0; i < t.NumField(); i++ {
  15. fields = append(fields, t.Field(i))
  16. if t.Field(i).Name == "Name" {
  17. fields[i].Tag = `yaml:"name"` // Dynamic annotation
  18. }
  19. }
  20. newType := reflect.StructOf(fields)
  21. newValue := reflect.NewAt(newType, unsafe.Pointer(u)).Elem()
  22. err := node.Decode(newValue.Addr().Interface())
  23. return err
  24. }
  25. var dat string = `name: abc`
  26. func main() {
  27. out := User{}
  28. yaml.Unmarshal([]byte(dat), &out)
  29. fmt.Printf("%+v\n", out)
  30. }

两个关键变化:
1.将newValue.Interface()替换为newValue.Addr().Interface()。(请参见此示例:https://pkg.go.dev/reflect#example-StructOf)
1.将newValue := value.Convert(newType)替换为newValue := reflect.NewAt(newType, unsafe.Pointer(u)).Elem()
我们这样做是因为value := reflect.ValueOf(*u)中的value是不可寻址的(您可以使用fmt.Printf("%v", value.Addr())来验证它。它会发出消息panic: reflect.Value.Addr of unaddressable value,从而引起死机)。

展开查看全部

相关问题