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")
}