我想动态更改struct
的注解,并使用yaml.Unmarshal
,如下所示:
package main
import (
"fmt"
"reflect"
"gopkg.in/yaml.v3"
)
type User struct {
Name string `yaml:"dummy"`
}
func (u *User) UnmarshalYAML(node *yaml.Node) error {
value := reflect.ValueOf(*u)
t := value.Type()
fields := make([]reflect.StructField, 0)
for i := 0; i < t.NumField(); i++ {
fields = append(fields, t.Field(i))
if t.Field(i).Name == "Name" {
fields[i].Tag = `yaml:"name"` // Dynamic annotation
}
}
newType := reflect.StructOf(fields)
newValue := value.Convert(newType)
err := node.Decode(newValue.Interface()) // Cause error because it's not pointer
return err
}
var dat string = `name: abc`
func main() {
out := User{}
yaml.Unmarshal([]byte(dat), &out)
fmt.Printf("%+v\n", out)
}
它会导致panic: reflect: reflect.Value.Set using unaddressable value [recovered]
这样的错误,我想这是因为node.Decode
没有和指针一起使用。那么如何创建新类型的指针呢?
1条答案
按热度按时间3wabscal1#
下面是更新后的演示:
两个关键变化:
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
,从而引起死机)。