douguai6716 2018-04-11 00:14
浏览 41
已采纳

使用反射设置nil * int32结构域

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:

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
}
  • 写回答

1条回答 默认 最新

  • doudu9652 2018-04-11 00:25
    关注

    There are two issues here. The first is that an addressable value is required. Pass a pointer to the struct to the function instead of the the struct value:

    replaceNilWithNegativeOne(&testStructInstance)
    

    In the function, call Value.Elem() to get the reflect value for the struct.

    The other issue is that the code assigns an int to an int32. Use int32(-1) to fix the problem.

    Here's the updated function with these changes:

    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

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥50 MATLAB APP 制作出现问题
  • ¥15 wannier复现图像时berry曲率极值点与高对称点严重偏移
  • ¥15 利用决策森林为什么会出现这样·的问题(关键词-情感分析)
  • ¥15 DispatcherServlet.noHandlerFound No mapping found for HTTP request with URI[/untitled30_war_e
  • ¥15 使用deepspeed训练,发现想要训练的参数没有梯度
  • ¥15 寻找一块做为智能割草机的驱动板(标签-stm32|关键词-m3)
  • ¥15 信息管理系统的查找和排序
  • ¥15 基于STM32,电机驱动模块为L298N,四路运放电磁传感器,三轮智能小车电磁组电磁循迹(两个电机,一个万向轮),怎么用读取的电磁传感器信号表示小车所在的位置
  • ¥15 如何解决y_true和y_predict数据类型不匹配的问题(相关搜索:机器学习)
  • ¥15 PB中矩阵文本型数据的总计问题。