如何使用反射提取接口类型名称和包?
How to extract the interface type name and package using reflection?
我需要使用反射知道类型名称及其路径。类型 Type
有一个 Name() 和 PkgPath() 方法,但如果类型是接口,它们 return 都是空的。
但是,如果我反映一个函数并提取其参数的类型信息,我将获得正确的类型信息。我应该假设这是前一种情况下的错误吗?不应该 TypeOf return 相同的类型信息而不考虑上下文(例如类型函数参数或值的类型)?
我知道类型断言,但我并不总是有一个值来做断言,所以我需要使用 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 是否实现接口的最佳方法是删除反射并使用如下类型断言:
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
使用接口类型。但是对于任何具体的变量,它将使用值的实际类型。
golang中有两种接口,又名eface和iface。而eface是一个空接口,可以简单的表示为interface {}
。 iface是一种至少有一个方法的接口,例如:
type MyInterface interface {
Greeting() string
}
在golang实现中,eface和iface都是two-word长结构。 eface保存数据和数据类型,iface保存数据、interfacetype和数据类型。当一个 iface 分配给一个 eface 时,interfacetype 信息被忽略。只有传递给eface的数据和数据类型。
因此,reflect.TypeOf(i interface{})
的参数是 eface,没有接口类型信息(在您的情况下又名 context.Context)。所以获取不到原来的interfacetype
我需要使用反射知道类型名称及其路径。类型 Type
有一个 Name() 和 PkgPath() 方法,但如果类型是接口,它们 return 都是空的。
但是,如果我反映一个函数并提取其参数的类型信息,我将获得正确的类型信息。我应该假设这是前一种情况下的错误吗?不应该 TypeOf return 相同的类型信息而不考虑上下文(例如类型函数参数或值的类型)?
我知道类型断言,但我并不总是有一个值来做断言,所以我需要使用 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 是否实现接口的最佳方法是删除反射并使用如下类型断言:
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
使用接口类型。但是对于任何具体的变量,它将使用值的实际类型。
golang中有两种接口,又名eface和iface。而eface是一个空接口,可以简单的表示为interface {}
。 iface是一种至少有一个方法的接口,例如:
type MyInterface interface {
Greeting() string
}
在golang实现中,eface和iface都是two-word长结构。 eface保存数据和数据类型,iface保存数据、interfacetype和数据类型。当一个 iface 分配给一个 eface 时,interfacetype 信息被忽略。只有传递给eface的数据和数据类型。
因此,reflect.TypeOf(i interface{})
的参数是 eface,没有接口类型信息(在您的情况下又名 context.Context)。所以获取不到原来的interfacetype