【问题标题】:Strange behavior for a pointer of an interface接口指针的奇怪行为
【发布时间】:2019-04-27 00:46:44
【问题描述】:

我写了 3 个类似的函数来找出 Go 的指针反射的奇怪行为。

package main

import (
    "reflect"
    "fmt"
)

var i interface{} = struct {}{}     // i is an interface which points to a struct
var ptr *interface{} = &i           // ptr is i's pointer

func f(x interface{}) {             // print x's underlying value
    fmt.Println(reflect.ValueOf(x).Elem())
}

func main1() {  // f is asking for interface? OK, I'll use the struct's interface
    structValue := reflect.ValueOf(ptr).Elem().Elem().Interface()
    f(structValue)
}

func main2() {  // Error? Let me try the struct's pointer
    structPtr := reflect.ValueOf(ptr).Elem().Interface()
    f(structPtr)
}

func main3() {  // Why this one could succeed after New() ?
    typ := reflect.ValueOf(ptr).Elem().Elem().Type()
    newPtr := reflect.New(typ).Elem().Addr().Interface()
    f(newPtr)
}

func main() {
    //main1()   // panic: reflect: call of reflect.Value.Elem on struct Value
    //main2()   // panic: reflect: call of reflect.Value.Elem on struct Value
    main3()     // OK. WHY???
}

只有 main3 工作,其他 2 会恐慌。为什么? 3 的主要区别在于它创造了一个新的价值。

关于main2,我认为ValueOf().Elem().Interface()已经重构了一个指向struct{}{}的接口,只是不明白为什么会失败。

【问题讨论】:

    标签: go reflection interface go-reflect


    【解决方案1】:

    从 reflect.ValueOf 返回的值包含存储在参数中的具体值。如果参数为 nil,则返回零 reflect.Value。

    换句话说,reflect.Value 和传递给 reflect.Value 的接口具有相同的底层值。

    如果您将f 更改为:

    func f(x interface{}) {             // print x's underlying value
        fmt.Println(reflect.ValueOf(x))
    }
    

    main3f 的参数是*struct{}。函数 f 取消引用指针(通过调用 Elem())并打印 struct{} 的反射值。

    可能令人困惑的一点是reflect.ValueOf(ptr).Elem().Elem().Interface()reflect.ValueOf(ptr).Elem().Interface() 返回具有相同具体值的接口。

    表达式reflect.ValueOf(ptr).Elem()i对应的反射值。对该值调用Interface() 会返回一个接口,该接口具有i 中的具体值。

    表达式reflect.ValueOf(ptr).Elem().Elem() 是对应i 的具体值的反射值。对该值调用Interface() 会返回一个包含该具体值的接口。

    【讨论】:

    • 之所以写 main1 和 main2 是因为我认为interface {} 是一种特殊的指针。或者,不是在 Golang 中吗?所以一个接口应该可以被ValueOf().Elem()调用...
    猜你喜欢
    • 1970-01-01
    • 2020-01-22
    • 2020-11-28
    • 2021-07-01
    • 2013-03-31
    • 2012-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多