I'm trying to set the value of a nil
*int
through reflection.
In the example below, replaceNilWithNegativeOne
should replace any nil
*int32
field (tagged with grib:"foo"
) with a pointer to -1.
However, when the code is run, reflect is panicking with panic: reflect: reflect.Value.Set using unaddressable value
.
I've seen almost the exact question I'm asking here in several other places, such as:
- Using reflect, how do you set the value of a struct field?
- Using reflect, how do you initialize value of a struct pointer field?
- reflect.Value.Set using unaddressable value
- Set a pointer to a field using reflection
- As well as non SO research.
I know the answer must be in those responses somewhere, but I am still having trouble connecting the dots. I've tried several implementations in addition to the one you see in the example below, but they all seem to either lead to either a segfault, or, more frequently, the unadressable value panic.
It is clear to me that fieldPtr.CanSet() == false
, but, that being said, how would I go about accomplishing what it is that I want to accomplish?
Example
// https://play.golang.org/p/yZOtYxwTzUs
package main
import (
"log"
"reflect"
"strings"
)
func main() {
type testStruct struct {
SomeField *int32 `grib:"foo"`
}
testStructInstance := testStruct{
SomeField: nil,
}
replaceNilWithNegativeOne(testStructInstance)
if *testStructInstance.SomeField != int32(-1) {
// We never get here
log.Println("Didn't get set")
}
}
func replaceNilWithNegativeOne(obj interface{}) (err error) {
objType := reflect.TypeOf(obj)
for i := 0; i < objType.NumField(); i++ {
if t, ok := objType.Field(i).Tag.Lookup("grib"); ok {
if strings.Contains(t, "foo") {
fieldPtr := reflect.ValueOf(obj).Field(i)
if fieldPtr.Kind() != reflect.Ptr {
// do some stuff
break
}
if fieldPtr.IsNil() {
v := -1
// I know this isn't working because the CanSet() == false
// But I want to set the value to -1.
fieldPtr.Set(reflect.ValueOf(&v))
continue
}
}
}
}
return
}