Golang 反射
学习目的
是否可以通过反射原理实现未知函数调用。
func funcName1(){}
func funcName2(){}
func funcName2(){}
func callfunc(funcName string) {
// 判断函数funcName是否存在?
// 调用函数
}
需求分析
在PHP当中,实现该需求非常容易,PHP当中可以使用以下代码实现:
<?php
function register() {
xxx
}
"register"()
但Golang中,对和数数据类型的强制验证,以及内部更深层次的实现原理,使得我们不得不通过其它方法来实现。经过查询文档,最终发现通过反射可以实现此需求。
方式一:通过反射
Golang中通过reflect来实现反射,其中两个比较重要的函数
reflect.TypeOf()
reflect.ValueOf()
通过TypeOf
可以获得类型的反射种类,反射种类大体如下:
type Kind uint
const (
Invalid Kind = iota // 非法类型
Bool // 布尔型
Int // 有符号整型
Int8 // 有符号8位整型
Int16 // 有符号16位整型
Int32 // 有符号32位整型
Int64 // 有符号64位整型
Uint // 无符号整型
Uint8 // 无符号8位整型
Uint16 // 无符号16位整型
Uint32 // 无符号32位整型
Uint64 // 无符号64位整型
Uintptr // 指针
Float32 // 单精度浮点数
Float64 // 双精度浮点数
Complex64 // 64位复数类型
Complex128 // 128位复数类型
Array // 数组
Chan // 通道
Func // 函数
Interface // 接口
Map // 映射
Ptr // 指针
Slice // 切片
String // 字符串
Struct // 结构体
UnsafePointer // 底层指针
)
通过ValueOf
可以获得类型的反射值,以下是通过反射实现的一个函数调用:
package main
import (
"fmt"
)
type Task struct {
name string
}
// 函数名一定要大写,不然反射获取不到函数列表
func (task *Task) RepayTask(body []byte) {
fmt.Printf("Repay Task Recv:%s\n", body)
}
// 函数名一定要大写,不然反射获取不到函数列表
func (task *Task) InvestTask(body []byte) {
fmt.Printf("Invest Task Recv:%s\n", body)
}
package main
import (
"fmt"
"reflect"
)
type Task struct {
name string
}
// 函数名一定要大写,不然反射获取不到函数列表
func (task *Task) RepayTask(body []byte) {
fmt.Printf("Repay Task Recv:%s\n", body)
}
// 函数名一定要大写,不然反射获取不到函数列表
func (task *Task) InvestTask(body []byte) {
fmt.Printf("Invest Task Recv:%s\n", body)
}
func main() {
t := &Task{}
v := reflect.ValueOf(t)
ele := v.Elem()
s := ele.Type()
fmt.Println(s.NumField())
fmt.Println(v.NumMethod())
arg := reflect.ValueOf("ABC")
v.MethodByName("RepayTask").Call([]reflect.Value{arg})
v.MethodByName("InvestTask").Call([]reflect.Value{arg})
}
方式二:通过匿名函数
var lock sync.RWMutex
var funcs map[string]func(name string) bool
// 注册函数
func Registry(key string,func func(name string) bool) {
# 处理并发问题
lock.Lock()
defer lock.Unlock()
funcs[key] = func
}
// 注册一个`isEmpty`函数
Registry("isEmpty",func(name string) bool{
if len(name)>0{
return false
}
return true
})
// 调用
if funcs["isEmpty"]("hello"){
println("is empty")
}