简体   繁体   中英

panic: reflect: call of reflect.Value.FieldByName on interface Value

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)

Run it on the Go playground .

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM