微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何使用反射将结构成员设置为指向任意值的指针

如何解决如何使用反射将结构成员设置为指向任意值的指针

注意:我想做与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

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

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{},所以需要通过反射来完成。

以下是前往“游乐场”的链接https://play.golang.org/p/zElEGHgx1IO

解决方法

使用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
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。