【golang/实验性】如何使用类型名进行实例化

文章目录

  • 说在前面
  • 问题提出
  • 其他语言
  • 注册式方法
  • 注册式处理指针类型
  • 神奇的方法
  • 接口调用
  • 参考

说在前面

  • 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{}之间的转换,最终调用到公共方法。

参考

  • How to discover all package types at runtime?
  • How to initialize struct pointer via reflection
  • Call a Struct and its Method by name in Go?
  • Create a new struct with reflect from type defined by a nil pointer

你可能感兴趣的:(Go,golang)