[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
}
相关推荐
何曾参静谧8 分钟前
「Py」Python基础篇 之 Python都可以做哪些自动化?
开发语言·python·自动化
Prejudices12 分钟前
C++如何调用Python脚本
开发语言·c++·python
我狠狠地刷刷刷刷刷25 分钟前
中文分词模拟器
开发语言·python·算法
wyh要好好学习28 分钟前
C# WPF 记录DataGrid的表头顺序,下次打开界面时应用到表格中
开发语言·c#·wpf
AitTech29 分钟前
C#实现:电脑系统信息的全面获取与监控
开发语言·c#
qing_04060331 分钟前
C++——多态
开发语言·c++·多态
孙同学_31 分钟前
【C++】—掌握STL vector 类:“Vector简介:动态数组的高效应用”
开发语言·c++
froginwe1132 分钟前
XML 编辑器:功能、选择与使用技巧
开发语言
Jam-Young38 分钟前
Python的装饰器
开发语言·python
man20171 小时前
【2024最新】基于springboot+vue的闲一品交易平台lw+ppt
vue.js·spring boot·后端