[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
}
相关推荐
微学AI8 小时前
一根针指向所有方向:挂谷猜想对 LLM Agent 技能-记忆架构的启示
开发语言·人工智能·架构·挂谷猜想
豆瓣鸡9 小时前
算法日记 - Day3
java·开发语言·算法
mldong9 小时前
从 mldong 到 jeeflow:一个工作流引擎的独立进化
后端
Achou.Wang9 小时前
深入理解go语言-第5章 并发编程——Go的灵魂
大数据·算法·golang
韭菜炒鸡肝天9 小时前
VTK开发笔记(一):VTK介绍,Qt..+VSx+VTK.编译
开发语言·笔记·qt
陈随易9 小时前
MoonBit抓包模块pcap,查看电脑的每一次联网通信
前端·后端·程序员
Aaron - Wistron10 小时前
Web API C# (Furion版)带 单元测试
开发语言·后端·c#
卷无止境10 小时前
写代码这件事,到底该讲究点什么?
后端·python
卷无止境10 小时前
循环复杂度到底在算什么,Python 代码怎么才能写得让人一看就懂
后端·python
Dxy123931021611 小时前
Python项目打包成EXE完整教程(PyInstaller实战避坑)
开发语言·python