I have a variable of type interface{}
and I want to change the value of a field using reflection. How can I do it? Variable must be of type interface{}
due to other requirements. If the variable isn't of type interface{}
all works, otherwise code throws
reflect: call of reflect.Value.FieldByName on interface Value
my code
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)
}
The application must call Elem()
twice to get the struct value:
reflect.ValueOf(&b).Elem().Elem().FieldByName("Name").SetString("Hello")
The first call Elem()
dereferences the pointer to interface{}
. The second call to Elem()
gets the value contained in the interface.
With this change, the panic is reflect.Value.SetString using unaddressable value
.
The application cannot set fields directly on the struct value contained in the interface because values contained in an interface are not addressable.
Copy the struct value to a temporary variable, set the field in the temporary variable and copy the temporary variable back to the interface.
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)
The interface b
is initialized using the value of the anonymous struct, so b
contains a copy of the struct, and the values are not addressable. Initialize b
using a pointer:
var b interface{}
b = &struct {
Name string
}{}
reflect.ValueOf(b).Elem().FieldByName("Name").SetString("Hello")
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.