问题描述
我的变量类型为interface{}
,我想使用反射更改字段的值。我有类型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
。
由于接口中包含的值不可寻址,因此应用程序无法直接在接口中包含的结构值上设置字段。
将struct值复制到临时变量,在临时变量中设置字段,然后将临时变量复制回接口。
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")