说在前面
- go版本:go1.14.1 windows/amd64
问题提出
- 已定义了一些结构体,这些结构体有一些通用的方法(
interface{}
),然后想要通过这个结构名去调用这些方法,由此引出了这个问题。 - 定义结构体
type XStruct strcut { Data int }
- 使用结构体名来实例化,例如
a := function("XStruct") fmt.Println(a.Data)
- 是否可行?
其他语言
- 在
java
中似乎是可以实现的,例如 这个 - 即
Class<?> clazz = Class.forName(className); Constructor<?> ctor = clazz.getConstructor(String.class); Object object = ctor.newInstance(new Object[] { ctorArgument });
注册式方法
- 这个
- 即
type XStruct struct { Data int } type YStruct struct { Data string } var typeRegistry = make(map[string]reflect.Type) // 注册 func Register() { typeList := []interface{ }{ &XStruct{ }, &YStruct{ }, } for idx := range typeList { inter := typeList[idx] typeRegistry[fmt.Sprintf("%T", inter)] = reflect.TypeOf(inter) } } func main() { Register() t, ok := typeRegistry["*main.XStruct"] if !ok { return } v := reflect.New(t) // 这个转换也太傻了 s := (*XStruct)(unsafe.Pointer(v.Pointer())) s.Data = 1 fmt.Println(s) }
PS E:\Mscript> go run .\main.go &{ 1}
注册式处理指针类型
- 这里
- 即(还是注册式):
type XStruct struct { Data int } func (this *XStruct) Out() { fmt.Println(this.Data) } type YStruct struct { Data string } var typeRegistry = make(map[string]reflect.Type) var valRegistry = make(map[string]reflect.Value) func Register() { typeList := []interface{ }{ new(XStruct), new(YStruct), } for idx := range typeList { inter := typeList[idx] typeRegistry[fmt.Sprintf("%T", inter)] = reflect.TypeOf(inter) valRegistry[fmt.Sprintf("%T", inter)] = reflect.ValueOf(inter) } } func main() { Register() t, ok := valRegistry["*main.XStruct"] if !ok { return } v := reflect.New(t.Type().Elem()).Interface() fmt.Println(v) }
神奇的方法
- 这个
- 即
|--common |--common.s |--handler.go |--main.go
common.s
TEXT ·typelinks(SB), $0-0 JMP reflect·typelinks(SB)
handler.go
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 { return unsafe.Pointer(uintptr(p) + x) }
main.go
最终会输出一堆func main() { sections, offsets := common.Typelinks() for i, base := range sections { for _, offset := range offsets[i] { typeAddr := common.Add(base, uintptr(offset), "") typ := reflect.TypeOf(*(*interface{ })(unsafe.Pointer(&typeAddr))) val := reflect.ValueOf(*(*interface{ })(unsafe.Pointer(&typeAddr))) fmt.Println(typ, val) } } }
注意:这种方式仅会输出该运行时使用到的内容,假设struct { root runtime.semaRoot; pad [40]uint8 } struct { runtime.gList; n int32 } struct { runtime.mutex; runtime.persistentAlloc } struct { scheme tls.SignatureScheme; minModulusBytes int; maxVersion uint16 } struct { size uint32; nmalloc uint64; nfree uint64 } struct { sync.Mutex; m sync.Map } struct { sync.Mutex; table [64]big.divisor } struct { sync.Once; val int } struct { user bool; runnable runtime.gQueue; n int32 } struct { v interface { }; tag string; l []string } struct { }
common
中有未使用的内容,那么将获取不到。
接口调用
- 可以为这些公共的方法定义一个
interface{}
,通过interface{}
之间的转换,最终调用到公共方法。