我正在尝试通过反思来设置nil
*int
的值。
在下面的示例中,replaceNilWithNegativeOne
应使用指向-1的指针替换任何nil
*int32
字段(标有grib:"foo"
)。
然而,当代码运行时,反映出现了panic: reflect: reflect.Value.Set using unaddressable value
恐慌。
我在其他几个地方看到了几乎所有我要问的确切问题,例如:
我知道答案必须在某些地方的答案中,但我仍然无法连接点。除了你在下面的例子中看到的那个之外,我已经尝试了几个实现,但它们似乎都导致了段错误,或者更常见的是,导致无法抑制的值恐慌。
我很清楚fieldPtr.CanSet() == false
,但是,话虽如此,我将如何完成我想要完成的任务?
示例
// 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
}
答案 0 :(得分:1)
这里有两个问题。首先是需要addressable值。将指向结构的指针传递给函数而不是结构值:
replaceNilWithNegativeOne(&testStructInstance)
在函数中,调用Value.Elem()
以获取结构的反射值。
另一个问题是代码将int分配给int32。使用int32(-1)来解决问题。
以下是更新后的功能:
replaceNilWithNegativeOne(obj interface{}) (err error) {
v := reflect.ValueOf(obj).Elem()
t := v.Type()
for i := 0; i < t.NumField(); i++ {
if grib, ok := t.Field(i).Tag.Lookup("grib"); ok {
if strings.Contains(grib, "foo") {
fv := v.Field(i)
if fv.Kind() != reflect.Ptr {
// do some stuff
break
}
if fv.IsNil() {
iv := int32(-1)
fv.Set(reflect.ValueOf(&iv))
continue
}
}
}
}
return nil
}