[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
}
相关推荐
Rust语言中文社区4 分钟前
【Rust日报】 walrus:分布式消息流平台,比 Kafka 快
开发语言·分布式·后端·rust·kafka
z***02607 分钟前
Spring Boot管理用户数据
java·spring boot·后端
多多*9 分钟前
Threadlocal深度解析 为什么key是弱引用 value是强引用
java·开发语言·网络·jvm·网络协议·tcp/ip·mybatis
Python×CATIA工业智造9 分钟前
Python多进程爬虫实战:豆瓣读书数据采集与法律合规指南
开发语言·爬虫·python
一只乔哇噻17 分钟前
java后端工程师+AI大模型进修ing(研一版‖day56)
java·开发语言·学习·算法·语言模型
美团测试工程师18 分钟前
软件测试面试题2025年末总结
开发语言·python·测试工具
N***H48619 分钟前
Skywalking介绍,Skywalking 9.4 安装,SpringBoot集成Skywalking
spring boot·后端·skywalking
F***741726 分钟前
PHP操作redis
开发语言·redis·php
zore_c32 分钟前
【C语言】数据在内存中的存储(超详解)
c语言·开发语言·数据结构·经验分享·笔记
程序员-周李斌37 分钟前
ArrayList 源码深度分析(基于 JDK 8)
java·开发语言·数据结构·算法·list