【问题标题】:Set nil *int32 struct field using reflection使用反射设置 nil *int32 结构字段
【发布时间】:2018-09-20 17:15:05
【问题描述】:

我正在尝试通过反射设置nil *int 的值。

在下面的示例中,replaceNilWithNegativeOne 应将任何 nil *int32 字段(标记为 grib:"foo")替换为指向 -1 的指针。

但是,当代码运行时,reflect 会出现 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
}

【问题讨论】:

    标签: go reflection


    【解决方案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
    }
    

    Playground Example

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-20
      • 1970-01-01
      • 2021-11-01
      • 2019-02-21
      • 1970-01-01
      相关资源
      最近更新 更多