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条)

报告相同问题?

悬赏问题

  • ¥15 ogg dd trandata 报错
  • ¥15 高缺失率数据如何选择填充方式
  • ¥50 potsgresql15备份问题
  • ¥15 Mac系统vs code使用phpstudy如何配置debug来调试php
  • ¥15 目前主流的音乐软件,像网易云音乐,QQ音乐他们的前端和后台部分是用的什么技术实现的?求解!
  • ¥60 pb数据库修改与连接
  • ¥15 spss统计中二分类变量和有序变量的相关性分析可以用kendall相关分析吗?
  • ¥15 拟通过pc下指令到安卓系统,如果追求响应速度,尽可能无延迟,是不是用安卓模拟器会优于实体的安卓手机?如果是,可以快多少毫秒?
  • ¥20 神经网络Sequential name=sequential, built=False
  • ¥16 Qphython 用xlrd读取excel报错