据我所知,反射包中没有类型发现机制,该机制希望您已经具有要检查的类型或值的实例。
还有 其他 方法可以发现正在运行的go包中的所有导出类型(尤其是结构)吗?
这是我希望拥有的(但不存在):
import "time" import "fmt" func main() { var types []reflect.Type types = reflect.DiscoverTypes(time) fmt.Println(types) }
最终目标是能够发现满足特定条件的程序包的所有结构,然后能够实例化这些结构的新实例。
顺便说一句,识别类型的注册功能对于我的用例 不是 有效的方法。
无论您是否认为这是一个好主意,这就是为什么我想要这种功能(因为我知道您会问):
我编写了一个代码生成实用程序,该实用程序可以加载源文件并构建AST以扫描嵌入指定类型的类型。该实用程序的输出是一组基于发现类型的go测试功能。我使用此工具go generate来创建测试功能,然后运行go test以执行生成的测试功能。每次测试更改(或添加新类型)时,我都必须重新运行go generate才能重新运行go test。这就是注册功能不是有效选项的原因。我想避免此go generate步骤,但这将需要我的实用程序成为正在运行的程序包导入的库。库代码需要以某种方式在扫描过程中扫描正在运行的名称空间,init()以查找嵌入预期库类型的类型。
go generate
go test
init()
(请参阅底部的2019更新)
警告 :未经测试且骇客。每当发布新版本的Go时可能会中断。
通过对Go的运行时进行一些修改,可以获得运行时知道的所有类型。在您自己的程序包中包含一个小的程序集文件,其中包含:
TEXT yourpackage·typelinks(SB), NOSPLIT, $0-0 JMP reflect·typelinks(SB)
在中yourpackage,声明函数原型(无主体):
yourpackage
func typelinks() []*typeDefDummy
除了类型定义:
type typeDefDummy struct { _ uintptr // padding _ uint64 // padding _ [3]uintptr // padding StrPtr *string }
然后只需调用typelinks,遍历切片并读取每个StrPtr作为名称。寻找那些以开头的人yourpackage。请注意,如果有两个yourpackage在不同路径中调用的包,则此方法将不会明确工作。
我可以以某种方式挂接到反射包中以实例化这些名称的新实例吗?
是的,假设d是type的值*typeDefDummy(请注意星号,非常重要):
d
*typeDefDummy
t := reflect.TypeOf(*(*interface{})(unsafe.Pointer(&d)))
现在t是一个reflect.Type可以实例化reflect.Values的值。
t
reflect.Type
reflect.Value
编辑:我测试并成功执行了此代码,并已将其作为要点上传。
调整软件包名称,并根据需要添加路径。
自从我最初发布此答案以来,发生了很多变化。这是对如何在2019年使用Go 1.11进行相同操作的简短描述。
$GOPATH/src/tl/tl.go
package tl import ( "unsafe" ) func Typelinks() (sections []unsafe.Pointer, offset [][]int32) { return typelinks() } func typelinks() (sections []unsafe.Pointer, offset [][]int32) func Add(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer { return add(p, x, whySafe) } func add(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer
$GOPATH/src/tl/tl.s
TEXT tl·typelinks(SB), $0-0 JMP reflect·typelinks(SB) TEXT tl·add(SB), $0-0 JMP reflect·add(SB)
main.go
package main import ( "fmt" "reflect" "tl" "unsafe" ) func main() { sections, offsets := tl.Typelinks() for i, base := range sections { for _, offset := range offsets[i] { typeAddr := tl.Add(base, uintptr(offset), "") typ := reflect.TypeOf(*(*interface{})(unsafe.Pointer(&typeAddr))) fmt.Println(typ) } } }