drs3925 2015-10-18 16:06
浏览 109
已采纳

如何使用反射提取接口类型名称和包?

I need to know the type name and its path using reflection. type Type has a Name() and PkgPath() method but both of them return empty if the type is an interface.

However if I reflect a function and extract the type information of its arguments I get the correct type information. Should I assume it's a bug in the former case? Shouldn't TypeOf return the same type information regardless the context(e.g. type function parameter or type of a value) ?

I'm aware of type assertion but I don't always have a value to do the assertion so I need to work with reflect.Type information.

package main

import (
    "fmt"
    "reflect"
    "golang.org/x/net/context"
)

func main() {
    c := reflect.TypeOf(withValue(""))
    fn := func(context.Context){}
    fc := reflect.TypeOf(fn).In(0)
    fmt.Println(isContext(c),  isContext(fc), c, fc)
}

func isContext(r reflect.Type) bool {
    return r.PkgPath() == "golang.org/x/net/context" && r.Name() == "Context"
}


func withValue(v interface{}) context.Context {
    return context.WithValue(context.TODO(), "mykey", v)
}

Prints

false true *context.valueCtx context.Context
  • 写回答

2条回答 默认 最新

  • dongsheng6056 2015-10-18 16:30
    关注

    Here is some working code: https://play.golang.org/p/ET8FlguA_C

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    type MyInterface interface {
        MyMethod()
    }
    
    type MyStruct struct{}
    
    func (ms *MyStruct) MyMethod() {}
    
    func main() {
        var structVar MyInterface = &MyStruct{}
        c := reflect.TypeOf(structVar)
    
        fn := func(MyInterface) {}
        fc := reflect.TypeOf(fn).In(0)
    
        fmt.Println(isMyInterface(c), isMyInterface(fc), c, fc)
        // OP expects : "true true main.MyInterface main.MyInterface"
    }
    
    func isMyInterface(r reflect.Type) bool {
        // TypeOf trick found at https://groups.google.com/forum/#!topic/golang-nuts/qgJy_H2GysY
        return r.Implements(reflect.TypeOf((*MyInterface)(nil)).Elem())
    }
    

    Here is my answer before I found an actual solution with reflect. I'm gonna let it here because I think it still has some interesting parts.


    First things first: for c, r.PkgPath() and r.Name() are empty because the underlying type is a pointer (*context.valueCtx).

    To fix that, you can use c := reflect.Indirect(reflect.ValueOf(withValue(""))).Type()

    But that does not make isContext(c) true, because you then have r.PkgPath() == "golang.org/x/net/context" && r.Name() == "valueCtx".

    The best way to check if a var implements an interface is to drop the reflection and use a type assertion like this:

    https://play.golang.org/p/td1YaHHej9

    package main
    
    import "fmt"
    
    type MyInterface interface {
        MyMethod()
    }
    
    type MyStruct struct{}
    
    func (ms *MyStruct) MyMethod() {}
    
    func main() {
        var structVar MyInterface = &MyStruct{}
    
        fmt.Println(isMyInterface(structVar))
    }
    
    func isMyInterface(object interface{}) bool {
        _, ok := object.(MyInterface)
        return ok
    }
    

    Your code works as you expect with the function parameter because there is no underlying value, so reflect uses the interface type. But for any concrete var, it will use the actual type of the value.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥20 求个正点原子stm32f407开发版的贪吃蛇游戏
  • ¥15 正弦信号发生器串并联电路电阻无法保持同步怎么办
  • ¥15 划分vlan后,链路不通了?
  • ¥20 求各位懂行的人,注册表能不能看到usb使用得具体信息,干了什么,传输了什么数据
  • ¥15 Vue3 大型图片数据拖动排序
  • ¥15 Centos / PETGEM
  • ¥15 划分vlan后不通了
  • ¥20 用雷电模拟器安装百达屋apk一直闪退
  • ¥15 算能科技20240506咨询(拒绝大模型回答)
  • ¥15 自适应 AR 模型 参数估计Matlab程序