[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
}