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

参考

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值