(请参阅底部的2019更新)
:未经测试且骇客。每当发布新版本的Go时可能会中断。
通过对Go的运行时进行一些修改,可以获得运行时知道的所有类型。在您自己的程序包中包含一个小的程序集文件,其中包含:
TEXT yourpackage·typelinks(SB), NOSPLIT, $0-0
JMP reflect·typelinks(SB)
在中yourpackage
,声明函数原型(无主体):
func typelinks() []*typeDefDummy
除了类型定义:
type typeDefDummy struct {
_ uintptr // padding
_ uint64 // padding
_ [3]uintptr // padding
StrPtr *string
}
然后只需调用typelinks,遍历切片并读取每个StrPtr作为名称。寻找那些以开头的人yourpackage
。请注意,如果有两个yourpackage
在不同路径中调用的包,则此方法将不会明确工作。
我可以以某种方式挂接到反射包中以实例化这些名称的新实例吗?
是的,假设d
是type的值*typeDefDummy
(请注意星号,非常重要):
t := reflect.TypeOf(*(*interface{})(unsafe.Pointer(&d)))
现在t
是一个reflect.Type
可以实例化reflect.Value
s的值。
自从我最初发布此答案以来,发生了很多变化。这是对如何在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)
}
}
}