Go语言中,函数的定义与函数的调用方可以不一致。换句话说,缺乏runtime类型安全就允许函数调用端的参数与函数定义端的参数不一致。Go不支持函数的多态特性,这就决定了无法根据参数的类型或者个数定义多态的函数。但是,可以定义多态参数。Go构建函数中,append, close, delete, copy, cap 和 len函数都使用了参数多态。
Go编程中,有时候为了达到代码的简洁美而编写一些泛化的函数。这些泛化的函数利用就是Go反射机制。
/**
目标函数模型为:
func CallTypeFunc(f func(A) B, ps []A) []B
*/
//Only support Go 1.1以上的发布版本
func CallTypeFunc(f interface{}, ps interface{}) interface{} {
vf := reflect.ValueOf(f)
vps := reflect.ValueOf(ps)
// 3) Map's return type must be `[]B1` where `B == B1`.
tys := reflect.SliceOf(vf.Type().Out(0))
vys := reflect.MakeSlice(tys, vps.Len(), vps.Len())
for i := 0; i < vps.Len(); i++ {
y := vf.Call([]reflect.Value{vps.Index(i)})[0]
vys.Index(i).Set(y)
}
return vys.Interface()
}
第一个函数的输入参数与第二个参数切片的类型相同,参数函数的返回类型与整个函数的返回类型相同,即泛化的模型为:func CallTypeFunc(f func(A) B, ps []A) []B
。
验证上面的函数,测试代码见下文。
fmt.Printf(" CallTypeFunc(func(x string) int { return len(x) }, []string{\"1\", \"10\", \"100\"}).([]int) return :%+v",
CallTypeFunc(func(x string) int { return len(x) }, []string{"1", "10", "100"}))
fmt.Printf(" CallTypeFunc(func(x int) int { return x*x }, []int{1, 10, 100}).([]int) return :%+v",
CallTypeFunc(func(x int) int { return x*x }, []int{1, 10, 100}))
//输出结果:
// CallTypeFunc(func(x string) int { return len(x) }, []string{"1", "10", "100"}).([]int) return :[1 2 3]
//CallTypeFunc(func(x int) int { return x*x }, []int{1, 10, 100}).([]int) return :[1 100 10000]
认真分析上面的代码,你会发现参数有bug。没有验证输入参数类型是否符合函数的参数定义。为了修复这个问题,需要加上参数验证逻辑。
待续下篇文章!
欢迎加入我的微信公众号