[go 反射] 函数

[go 反射] 函数

go 函数反射的基础认识

  • 输入参数
  • 返回输出

输入参数和输出

NumIn()此方法属于reflect.Type接口,用于获取参数数量;In(int)用于获取对应位置的参数
NumOut()此方法属于reflect.Type接口,用于获取返回变量的数量;Out(int)用于获取对应位置的返回变量

演示

go 复制代码
var one func(string,int,bool)int

tp:=reflect.TypeOf(one)
fmt.Println(tp.NumIn(),tp.NumOut())
//从左到右依次输出输入参数的变量基础类型
for i:=0;i<tp.NumIn();i++{
    fmt.Println(tp.In(i).Kind())
}
//依次输出返回变量的基础类型
for i:=0;i<tp.NumOut();i++{
    fmt.Println(tp.Out(i).Kind())
}

反射运行函数

Call([]reflect.Value)[]relfect.Value属于reflect.Value结构体的方法,运行此方法即可达到调用函数的目的,参数通过反射过后放入数组内给call

演示

go 复制代码
func Greet(name string)string{
    fmt.Println("call greet function")
    return "hello "+name
}
func main(){
    tp:=reflect.TypeOf(Greet)
    vl:=reflect.ValueOf(Greet)
    input:="jim"
    fmt.Println(tp.NumIn(),tp.NumOut())//两者都是1
    ans:=vl.Call([]reflect.Value{reflect.ValueOf(input)})
    reflect.ValueOf(&input).Elem().Set(ans[0])//将结果替换掉原来的input
    fmt.Println(input)
}

终极实现------任意函数调用接口

go 复制代码
//能够通过此方法调用任意现存函数,并返回到结构体
func AnyFunc[T any](src any, dst *T, args ...any) (err error) {
	stp, dtp := reflect.TypeOf(src), reflect.TypeOf(dst).Elem()
	svl, dvl := reflect.ValueOf(src), reflect.ValueOf(dst).Elem()
	if svl.IsNil() || stp.Kind() != reflect.Func {
		err = str_error("src function invaild")
		return
	}
	if stp.NumIn() != len(args) {
		err = str_error("args can't match the function args")
		return
	}
	var argsvl []reflect.Value = make([]reflect.Value, len(args))
	for i, ele := range args {
		argsvl[i] = reflect.ValueOf(ele)
	}
	outvl := svl.Call(argsvl)
	outcount := stp.NumOut()
	if dst == nil && outcount > 0 {
		err = str_error("dst is null")
		return
	}
	if outcount == 1 {
		if dtp == outvl[0].Type() {
			if dvl.CanSet() {
				dvl.Set(outvl[0])
			} else {
				err = str_error("dst can't be set")
			}
		} else {
			err = str_error("dst type is don't match")
		}
	} else if outcount > 1 {
		if dtp.Kind() == reflect.Struct {//结构体非严格匹配赋值,请看[go 反射] 结构体
			if dtp.NumField() >= outcount {
				var i, j = 0, 0
				var anspos []int = make([]int, 0, outcount)
				for i < dtp.NumField() && j < outcount {
					if dtp.Field(i).Type == outvl[j].Type() {
						if dvl.Field(i).CanSet() {
							anspos = append(anspos, i)
						}
						j++
					}
					i++
				}
				if len(anspos) == outcount {
					for key, pos := range anspos {
						dvl.Field(pos).Set(outvl[key])
					}
				} else {
					err = str_error("precheck failed")
				}
			} else {
				err = str_error("your recieve struct fields not enough")
			}
		} else if dtp.Kind() == reflect.Map {
			if dvl.IsNil() {
				dvl.Set(reflect.MakeMap(dtp))
			}
		} else {
			err = str_error("you should use struct pointer to recieve return ans")
		}
	}
	return
}
相关推荐
952365 小时前
MyBatis
后端·spring·mybatis
FQNmxDG4S7 小时前
Java多线程编程:Thread与Runnable的并发控制
java·开发语言
前端老石人7 小时前
HTML 字符引用完全指南
开发语言·前端·html
matlab_xiaowang8 小时前
Redux 入门:JavaScript 可预测状态管理库
开发语言·javascript·其他·ecmascript
虹科网络安全8 小时前
艾体宝干货|数据复制详解:类型、原理与适用场景
java·开发语言·数据库
axng pmje8 小时前
Java语法进阶
java·开发语言·jvm
uzong8 小时前
9 种 RAG 架构,每位 AI 开发者必学:完整实战指南
后端
老前端的功夫9 小时前
【Java从入门到入土】28:Stream API:告别for循环的新时代
java·开发语言·python
qq_435287929 小时前
第9章 夸父逐日与后羿射日:死循环与进程终止?十个太阳同时值班的并行冲突
java·开发语言·git·死循环·进程终止·并行冲突·夸父逐日
小江的记录本9 小时前
【Kafka核心】架构模型:Producer、Broker、Consumer、Consumer Group、Topic、Partition、Replica
java·数据库·分布式·后端·搜索引擎·架构·kafka