[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
}
相关推荐
oak隔壁找我7 小时前
MySQL中 SHOW FULL PROCESSLIST` 输出中 `State` 列的所有可能值
后端
上进小菜猪7 小时前
基于 YOLOv8 的面向文档智能处理的表格区域检测系统 [目标检测完整源码]
后端
oak隔壁找我8 小时前
JVM常用调优参数
java·后端
IT_陈寒11 小时前
React状态管理终极对决:Redux vs Context API谁更胜一筹?
前端·人工智能·后端
晨星shine12 小时前
GC、Dispose、Unmanaged Resource 和 Managed Resource
后端·c#
蝎子莱莱爱打怪12 小时前
OpenClaw 从零配置指南:接入飞书 + 常用命令 + 原理图解
java·后端·ai编程
倚栏听风雨12 小时前
【ES避坑指南】明明存的是 "CodingAddress",为什么 term 查询死活查不到?彻底搞懂 text 和 keyword
后端
程序员爱钓鱼13 小时前
Go 操作 Windows COM 自动化实战:深入解析 go-ole
后端·go·排序算法
回家路上绕了弯13 小时前
深入解析Agent Subagent架构:原理、协同逻辑与实战落地指南
分布式·后端
子玖13 小时前
实现微信扫码注册登录-基于参数二维码
后端·微信·go