我有一个类型为
interface{}
的变量,我想使用反射更改字段的值。我该怎么做呢?由于其他要求,变量必须是 interface{}
类型。如果变量不是类型 interface{}
则一切正常,否则代码会抛出
reflect: call of reflect.Value.FieldByName on interface Value
我的代码
package main
import (
"fmt"
"reflect"
)
func main() {
a := struct {
Name string
}{}
// works
reflect.ValueOf(&a).Elem().FieldByName("Name").SetString("Hello")
fmt.Printf("%#v\n", a)
var b interface{}
b = struct {
Name string
}{}
// panics
reflect.ValueOf(&b).Elem().FieldByName("Name").SetString("Hello")
fmt.Printf("%#v\n", b)
}
应用程序必须调用
Elem()
两次才能获取结构值:
reflect.ValueOf(&b).Elem().Elem().FieldByName("Name").SetString("Hello")
第一次调用
Elem()
取消引用指向 interface{}
的指针。 第二次调用 Elem()
获取接口中包含的值。
有了这个变化,恐慌就
reflect.Value.SetString using unaddressable value
。
应用程序无法直接在接口中包含的结构体值上设置字段,因为接口中包含的值不可寻址。
将结构体值复制到临时变量,设置临时变量中的字段并将临时变量复制回接口。
var b interface{}
b = struct {
Name string
}{}
// v is the interface{}
v := reflect.ValueOf(&b).Elem()
// Allocate a temporary variable with type of the struct.
// v.Elem() is the vale contained in the interface.
tmp := reflect.New(v.Elem().Type()).Elem()
// Copy the struct value contained in interface to
// the temporary variable.
tmp.Set(v.Elem())
// Set the field.
tmp.FieldByName("Name").SetString("Hello")
// Set the interface to the modified struct value.
v.Set(tmp)
fmt.Printf("%#v\n", b)
接口
b
使用匿名结构体的值进行初始化,因此 b
包含该结构体的副本,并且这些值是不可寻址的。使用指针初始化 b
:
var b interface{}
b = &struct {
Name string
}{}
reflect.ValueOf(b).Elem().FieldByName("Name").SetString("Hello")
更改编程语言。