为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
凤凰求蛊 2021-11-15 17:08:31
我需要使用反射知道类型名称及其路径。typeType有 Name() 和 PkgPath() 方法,但如果类型是接口,它们都返回空。但是,如果我反映一个函数并提取其参数的类型信息,我会得到正确的类型信息。我应该假设这是前一种情况下的错误吗?无论上下文如何(例如类型函数参数或值的类型),TypeOf 不应该返回相同的类型信息吗?我知道类型断言,但我并不总是有一个值来进行断言,所以我需要使用reflect.Type 信息。package mainimport (    "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)}印刷false true *context.valueCtx context.Context
查看完整描述

2 回答

?
森栏

TA贡献1810条经验 获得超5个赞

这是一些工作代码: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())

}

这是我在找到实际解决方案之前的答案reflect。我会放在这里,因为我认为它仍然有一些有趣的部分。


首先要做的事情是: for c、 r.PkgPath() 和 r.Name() 是空的,因为底层类型是指针 ( *context.valueCtx)。


要解决这个问题,您可以使用 c := reflect.Indirect(reflect.ValueOf(withValue(""))).Type()


但这并不isContext(c)成立,因为你有r.PkgPath() == "golang.org/x/net/context" && r.Name() == "valueCtx".


检查 var 是否实现接口的最佳方法是删除反射并使用这样的类型断言:


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

}

您的代码使用函数参数按预期工作,因为没有基础值,因此reflect使用接口类型。但是对于任何具体的 var,它将使用值的实际类型。


查看完整回答
反对 回复 2021-11-15
?
慕虎7371278

TA贡献1802条经验 获得超4个赞

golang 中有两种接口,即eface和iface。而 eface 是一个空接口,可以简单地表示为interface {}. iface 是一种至少具有一种方法的接口,例如:


type MyInterface interface {

    Greeting() string

}

在 golang 实现中,eface 和 iface 都是两个字长的结构体。eface 保存数据和数据类型,iface 保存数据、接口类型和数据类型。当 iface 分配给 eface 时,将忽略 interfacetype 信息。只有传递给 eface 的数据和数据类型。


因此,reflect.TypeOf(i interface{})的参数是和 eface,没有接口类型信息(在您的情况下也称为 context.Context)。所以你不能得到原始的接口类型。


查看完整回答
反对 回复 2021-11-15
  • 2 回答
  • 0 关注
  • 158 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信