如何通过反射初始化struct指针

时间:2017-07-12 15:12:14

标签: go reflection

我的目标是使用nil指向结构的指针(但可以是任何类型),作为interface{}传递,并在其位置初始化结构。

我的测试代码(playground link)是:

package main

import (
    "fmt"
    "reflect"
)

type Foo struct {
    Foo string
}

func main() {
    var x *Foo
    var y interface{} = x
    fmt.Printf("Before: %#v\n", y)
    fmt.Printf("Goal: %#v\n", interface{}(&Foo{}))

    rv := reflect.ValueOf(y)
    rv.Set(reflect.New(rv.Type().Elem()))

    fmt.Printf("After: %#v\n", y)
}

我希望代码是自我记录的。但目标本质上是将y转换为指向Foo的初始化(零值)实例的指针,该(*main.Foo)(nil)以未初始化的指针Foo,(&main.Foo{Foo:""})开头。 :reflect.Value.Set using unaddressable value。但是我得到了interface{}。我不明白为什么我试图设定的价值无法追究。我花了一天时间阅读源代码到标准库JSON unmarshaler和其他SO帖子,但我仍然清楚地忽略了一些东西。

如果我剥离外rv := reflect.ValueOf(y).Elem() // Remove the outer interface{} rv.Set(reflect.New(rv.Type().Elem()))

reflect: call of reflect.Value.Type on zero Value

错误变为sudo apt install python3-mysqldb

3 个答案:

答案 0 :(得分:3)

试试这个:

var x *Foo
var y interface{} = x
fmt.Printf("Before: %#v\n", y)
fmt.Printf("Goal: %#v\n", interface{}(&Foo{}))

// Must take address of y to set it. Dereference with Elem() to get value for y
rv := reflect.ValueOf(&y).Elem()

// Interface element type is *main.Foo, dereference with Elem() to get main.Foo
t := rv.Elem().Type().Elem()
rv.Set(reflect.New(t))
fmt.Printf("After: %#v\n", y)

playground example

您也可以指定y,而不是通过反射设置它:

var x *Foo
var y interface{} = x
fmt.Printf("Before: %#v\n", y)
fmt.Printf("Goal: %#v\n", interface{}(&Foo{}))
rv := reflect.ValueOf(y)
t := rv.Type().Elem()
y = reflect.New(t).Interface()
fmt.Printf("After: %#v\n", y)

playground example

答案 1 :(得分:1)

在您的示例中,rv.CanAddr()false,因此您无法对其进行设置(rv.CanSet()false)。

问题:如果你有一个指向nil的指针它就不可寻址。但是指向nil(或指向接口的指针)的指针是可寻址的。

你可以让你的榜样以不同的方式运作:

  • 初始化x为非零(可能不是这里的重点)
  • 将y设置为reflect.New(..)

    的新值
    func main() {
        var x *Foo
        var y interface{} = x
        fmt.Printf("Before: %#v\n", y)
        fmt.Printf("Goal: %#v\n", interface{}(&Foo{}))
    
        rv := reflect.ValueOf(y)
        y = reflect.New(rv.Type().Elem()).Interface()
    
        fmt.Printf("After: %#v\n", y)
    }
    

答案 2 :(得分:1)

在不知道您的实际使用情况的情况下,很难说您需要什么样的解决方案,但this works为您的示例:

var x *Foo
var y interface{} = x
rv := reflect.ValueOf(y)
y = reflect.New(rv.Type().Elem()).Interface()