反思思考结构价值也是一个ptr?

coo*_*ter 3 reflection go

我有一个像这个演示的数据结构.如您所见,foo有一个嵌入式指针指向bar:

type foo struct {
    *bar
}

type bar struct {
    S []byte
}
Run Code Online (Sandbox Code Playgroud)

我正在使用这样的reflect包:

func test(x interface{}) {

    var v = reflect.ValueOf(x)

    if v.Kind() == reflect.Struct {
        fmt.Println("was a struct")

    // panic: reflect: call of reflect.Value.Elem on struct Value
    //  v = v.Elem()

    // panic: reflect: call of reflect.Value.Field on ptr Value
        v = v.FieldByName("S")
    }
}

func main() {
    var f foo
    test(f)
    fmt.Println(string(f.S))
}
Run Code Online (Sandbox Code Playgroud)

所以v.Kind()被认为是一个reflect.Struct,但如果我试图通过使用它来像对待它一样.FieldByName("S"),它会因为它认为v是恐慌而恐慌ptr.

那么如果我试着把它当成一个ptr叫做电话.Elem(),它就会因为它认为v是恐慌而恐慌struct.

我已经尝试过reflect.Indirect(),以及其他一些事情,但我无法弄清楚如何获得嵌入式指针的字段.

有没有办法reflect.Value从嵌入式指针到结构获取表示?

演示: http : //play.golang.org/p/n0eea6XW3I


编辑:也试过v = v.FieldByName("bar"),但得到了:

panic: runtime error: invalid memory address or nil pointer dereference

Lin*_*ope 7

我们需要意识到的第一件事就是线条var f foo相当于f := foo{}.这会将内部字段bar(类型为*bar)初始化为零值... nil.嵌入类型和反射的行为似乎是它将嵌入类型的字段视为类型本身的字段.所以当你要求v.FieldByName("S")它试图在f的成员中找到那个字段时,bar,这是零.

你正试图这样做(*f.bar).S.(在Go中,不需要显式指针解除引用,但它确实如此).现在的问题是:如果你改变是v.FieldByName("bar")为什么它会出错?同样的道理.

仔细观察堆栈跟踪,FieldByName线路不再崩溃,崩溃的线路fmt.Println(string(f.S)).再一次,语义上你正在做(*f.bar).S.但是成员"bar"是零,所以你实际上是在做一个nil指针取消引用.

您可以通过更改var f foo为修复这两个错误f := foo{&bar{}}.

  • @cookiemonster错误信息肯定令人困惑.它应该真的说"尝试取消引用nil指针",而不是给你一个奇怪的"reflect.Field on pointer"错误. (2认同)