Go语言学习笔记之反射用法详解

2020-01-28 12:41:26王旭

type X struct {}
func (X) Format(s string, a ...interface{}) string {
    return fmt.Sprintf(s, a...)
}
func main() {
    var a X
    v := reflect.ValueOf(&a)
    m := v.MethodByName("Format")
    out := m.Call([]reflect.Value{
        reflect.ValueOf("%s = %d"), // 所有参数都须处理
        reflect.ValueOf("x"),
        reflect.ValueOf(100),
    })
    fmt.Println(out)
    out = m.CallSlice([]reflect.Value{
        reflect.ValueOf("%s = %d"),
        reflect.ValueOf([]interface{}{"x", 100}),
    })
    fmt.Println(out)
}

输出:


[x = 100]
[x = 100]

无法调用非导出方法,甚至无法获取有效地址。

四、构建

反射库提供了内置函数 make()new() 的对应操作,其中最有意思的就是 MakeFunc()。可用它实现通用模板,适应不同数据类型。
// 通用算法函数
func add(args []reflect.Value) (results []reflect.Value) {
    if len(args) == 0 {
        return nil
    }
    var ret reflect.Value
    switch args[0].Kind() {
    case reflect.Int:
        n := 0
        for _, a := range args {
            n += int(a.Int())
        }
        ret = reflect.ValueOf(n)
    case reflect.String:
        ss := make([]string, 0, len(args))
        for _, s := range args {
            ss = append(ss, s.String())
        }
        ret = reflect.ValueOf(strings.Join(ss, ""))
    }
    results = append(results, ret)
    return
}
// 将函数指针参数指向通用算法函数
func makeAdd(fptr interface{}) {
    fn := reflect.ValueOf(fptr).Elem()
    v := reflect.MakeFunc(fn.Type(), add) // 这是关键
    fn.Set(v)                             // 指向通用算法函数