【问题标题】:How to set a struct member that is a pointer to an arbitrary value using reflection如何使用反射设置作为指向任意值的指针的结构成员
【发布时间】:2020-09-30 13:03:57
【问题描述】:

注意:我想和How to set a struct member that is a pointer to a string using reflection in Go 做同样的事情,但以更通用的方式。现有的问题并没有解决我的问题。

我有想要使用反射填充的具有不同类型字段的结构:

type MyStruct struct {
    SomeInt       int
    SomeString    string
    SomeIntPtr    *int
    SomeStringPtr *string
}

我要写入各个字段的值从配置存储中检索并解析为正确的类型,类似于:

func getValueForField(fieldName string) interface{}

对于int*int 类型,该函数返回一个int(包装在一个接口中)。对于string*string,函数返回string(在接口后面)等等,适用于所有类型。

--> 请注意,它确实返回*int/*string!

现在我想将值分配给结构字段:

var field reflect.Value  = reflect.ValueOf(ptrToMyStruct).Elem().Field(i)
var value interface{}    = getValueForField(....)
var isPointer bool       = field.Kind() == reflect.Ptr

// assign "value" to "field":
if isPointer {
    // ??
    field.Set(reflect.ValueOf(value).Addr()) // panic: reflect.Value.Addr of unaddressable value
} else {
    field.Set(reflect.ValueOf(value)) // works
}

将这些值分配给具体类型很容易并且可以按预期工作。但是我无法将int 类型(从getValueForField 返回)分配给*int 字段,而无需以某种方式获得地址。由于我只有一个interface{},这需要通过反射来完成。

这是 Go Playground 的链接:https://play.golang.org/p/zElEGHgx1IO

【问题讨论】:

    标签: go pointers struct reflection


    【解决方案1】:

    使用reflect.New()为字段构造一个新的指针值,从value设置指向的值,然后将这个新值设置到指针字段。

    例如:

    type MyStruct struct {
        SomeIntPtr    *int
        SomeStringPtr *string
    }
    
    var ms MyStruct
    
    // Set int pointer
    {
        var i interface{} = 3 // of type int
    
        f := reflect.ValueOf(&ms).Elem().FieldByName("SomeIntPtr")
        x := reflect.New(f.Type().Elem())
        x.Elem().Set(reflect.ValueOf(i))
        f.Set(x)
    }
    
    // Set string pointer
    {
        var i interface{} = "hi" // of type string
    
        f := reflect.ValueOf(&ms).Elem().FieldByName("SomeStringPtr")
        x := reflect.New(f.Type().Elem())
        x.Elem().Set(reflect.ValueOf(i))
        f.Set(x)
    }
    
    fmt.Println("ms.SomeIntPtr", *ms.SomeIntPtr)
    fmt.Println("ms.SomeStringPtr", *ms.SomeStringPtr)
    

    这将输出(在Go Playground 上尝试):

    ms.SomeIntPtr 3
    ms.SomeStringPtr hi
    

    所以您的代码可能如下所示:

    // assign "value" to "field":
    if isPointer {
        x := reflect.New(field.Type().Elem())
        x.Elem().Set(reflect.ValueOf(value))
        field.Set(x)
    } else {
        field.Set(reflect.ValueOf(value)) // works
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-12
      • 1970-01-01
      • 2019-12-19
      • 2010-12-07
      • 2022-10-14
      • 1970-01-01
      • 2015-01-24
      相关资源
      最近更新 更多