reflection - 如何使用反射提取接口(interface)类型名称和包?

标签 reflection go

我需要使用反射知道类型名称及其路径。 type Type 有一个 Name() 和 PkgPath() 方法,但如果类型是一个接口(interface),它们都返回空。

但是,如果我反射(reflect)一个函数并提取其参数的类型信息,我将获得正确的类型信息。我应该假设这是前一种情况下的错误吗? TypeOf 不应该不管上下文(例如类型函数参数或值的类型)都返回相同的类型信息吗?

我知道类型断言,但我并不总是有一个值来进行断言,所以我需要使用 reflect.Type 信息。

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

打印

false true *context.valueCtx context.Context

最佳答案

这是一些工作代码: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 找到实际解决方案之前的回答。 我要把它放在这里,因为我认为它仍然有一些有趣的部分。


第一件事:对于 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 是否实现接口(interface)的最佳方法是删除反射并使用如下类型断言:

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 使用接口(interface)类型。但是对于任何具体的 var,它将使用值的实际类型。

关于reflection - 如何使用反射提取接口(interface)类型名称和包?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33200095/

相关文章:

linux - golang 可用无线网络列表(Linux 下)

go - 写入网络映射的驱动器时出现Fprintf错误

java - 为什么Java和Go的gzip会得到不同的结果?

exception-handling - 在 Golang 中捕捉 panic

arrays - 从两个 slice 的重复项创建一个 slice

c# - 如何使用 FastMember 设置嵌套属性值

java - 我可以构建一个知道该子类的某些属性值的子类实例吗

haskell - 动态获取某个类型的数据构造函数列表

c# - 如何知道 C# 中属性位置的层次结构?

java.lang.IllegalArgumentException : object is not an instance of declaring class 异常