广西住房建设厅网站首页,公司介绍怎么写范本,海淀搜索引擎优化seo,做词云图的网站引言
go语言中#xff0c;如果某个数据类型实现了一系列的方法#xff0c;如何批量去执行呢#xff0c;这时候就可以利用反射里的func (v Value) Call(in []Value) []Value 方法。
// Call calls the function v with the input arguments in.
// For example, if len(in)…引言
go语言中如果某个数据类型实现了一系列的方法如何批量去执行呢这时候就可以利用反射里的func (v Value) Call(in []Value) []Value 方法。
// Call calls the function v with the input arguments in.
// For example, if len(in) 3, v.Call(in) represents the Go call v(in[0], in[1], in[2]).
// Call panics if vs Kind is not Func.
// It returns the output results as Values.
// As in Go, each input argument must be assignable to the
// type of the functions corresponding input parameter.
// If v is a variadic function, Call creates the variadic slice parameter
// itself, copying in the corresponding values.
func (v Value) Call(in []Value) []Value {v.mustBe(Func)v.mustBeExported()return v.call(Call, in)
}Call方法实际使用时主要有以下两种调用方式
方法1使用reflect.Type.Method.Func.Call
package mainimport (fmtreflect
)type dog struct {name string
}func (a *dog) Speak() {fmt.Println(speaking!)
}
func (a *dog) Walk() {fmt.Println(walking!)
}func (a *dog) GetName() (string, error) {fmt.Println(Getting name!)return a.name, nil
}
func main() {var tudou dog{name: tudou}// 获取reflect.TypeobjectType : reflect.TypeOf(tudou)// 批量执行方法for i : 0; i objectType.NumMethod(); i {fmt.Printf(Now method: %v is being executed...\n, objectType.Method(i).Name)// Call的第一个入参对应receiver即方法的接受者本身ret : objectType.Method(i).Func.Call([]reflect.Value{reflect.ValueOf(tudou)})fmt.Printf(The return of method: %s is %v\n\n, objectType.Method(i).Name, ret)}
}注 1、这里说明下为什么使用Func调用Call时第一个入参是对应receiver本身method.Func.Call([]reflect.Value{reflect.ValueOf(tudou)}) 可以看下结构体Method中Func的定义有这么一句注释func with receiver as first argument
/** The compiler knows the exact layout of all the data structures above.* The compiler does not know about the data structures and methods below.*/// Method represents a single method.
type Method struct {...Func Value // func with receiver as first argument...
}2、objectType.Method(i)返回的是一个Method结构体
方法2使用reflect.Value.Method(index).Call
package mainimport (fmtreflect
)type dog struct {name string
}func (a *dog) Speak() {fmt.Println(speaking!)
}func (a *dog) SetName(name string) error {fmt.Println(Setting name!)a.name namereturn nil
}func (a *dog) GetName() (string, error) {fmt.Println(Getting name!)return a.name, nil
}func main() {var tudou dog{name: tudou}// 获取reflect.ValueobjectValue : reflect.ValueOf(tudou)// 根据方法名获取method执行CallobjectValue.MethodByName(Speak).Call(nil)objectValue.MethodByName(SetName).Call([]reflect.Value{reflect.ValueOf(newName)})objectValue.MethodByName(GetName).Call(nil)
}注 1、不同于方法1使用reflect.Value.Method直接调用Call不需要使用receiver作为第一个入参。可以看下方法MethodByName的注释有这么一句The arguments to a Call on the returned function should not include a receiver
// MethodByName returns a function value corresponding to the method
// of v with the given name.
// The arguments to a Call on the returned function should not include
// a receiver; the returned function will always use v as the receiver.
// It returns the zero Value if no method was found.
func (v Value) MethodByName(name string) Value {if v.typ nil {panic(ValueError{reflect.Value.MethodByName, Invalid})}if v.flagflagMethod ! 0 {return Value{}}m, ok : v.typ.MethodByName(name)if !ok {return Value{}}return v.Method(m.Index)
}2、objectValue.MethodByName(Speak)返回的是一个reflect.Value这个跟方法1调用Method()有明显区别
3、另外值得留意的是虽然方法2可以参考方法1的for循环批量执行method但是reflect.Value似乎并没有直接提供方法获取每一个method的Name。但是我们可以根据Index借助reflect.Type.Method(Index).Name来获取Name这是因为每一个method的Name和Index是一一对应的
type Method struct {// Name is the method name.Name string...Index int // index for Type.Method
}其实注1里的方法func (v Value) MethodByName(name string) Value 里有一段也是根据这个对应关系实现的m, ok : v.typ.MethodByName(name) ... return v.Method(m.Index)有兴趣的同学可以留意观察下