《The.Go.Programming.Language.2015.11》之 reflect

KingEasternSun · · 942 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

判断reflect.Value类型并提取数据

对于reflect.Value类型数据,根据Kind()进行判断

func formatAtom(v reflect.Value) string {
    switch v.Kind() {
    case reflect.Invalid:
        return "invalid"
    case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int8, reflect.Int64:
        return strconv.FormatInt(v.Int(), 10)
    case reflect.Bool:
        return strconv.FormatBool(v.Bool())
    case reflect.String:
        return v.String()
    default:
        return "no ex"
    }
}

对于其他复杂类型的数据

func display(path string, v reflect.Value) {
    switch v.Kind() {
    case reflect.Invalid:
        fmt.Println("")
    case reflect.Slice, reflect.Array:
        for i := 0; i < v.Len(); i++ {
            display(fmt.Sprintf("%s[%d]", path, i), v.Index(i))
        }
    case reflect.Struct:
        for i := 0; i < v.NumField(); i++ {
            fieldPath := fmt.Sprintf("%s[%s]", path, v.Type().Field(i).Name)
            display(fieldPath, v.Field(i))
        }
    case reflect.Map:
        for _, key := range v.MapKeys() {
            display(fmt.Sprintf("[%s][%s]", path, formatAtom(key)), v.MapIndex(key))
        }
    default:
        fmt.Printf("%s=%s\n", path, formatAtom(v))
    }

}

注意,对于结构体利用v.Type().Field(i).Name获取域名,利用v.Field(i)获取域值。

addressable

利用CanAddr()成员判断判断是否addressable。
如下变量d是addressable的,可以利用d.Set(reflect.ValueOf(11))进行赋值。
也可以利用d.Addr().Interface().(*int)转为指针再设置值,也可以利用d.SetInt(99)赋值:

func addressable_main() {
    x := 2
    d := reflect.ValueOf(&x).Elem()
    fmt.Println(d.CanAddr())

    d.Set(reflect.ValueOf(11))
    fmt.Println(x)

    dp := d.Addr().Interface().(*int)
    *dp = 12
    fmt.Println(x)

    d.SetInt(99)
    fmt.Println(x)
}

如下:对于int类型的变量x,使用rx.SetString("hello")会引起panic。对于interface{}类型的变量y,既可以使用ry.Set(reflect.ValueOf(3)),也可以使用ry.Set(reflect.ValueOf("hello")),但是使用ry.SetInt(2)会引起panic.

func addressable_main2() {
    x := 2
    rx := reflect.ValueOf(&x).Elem()
    rx.SetInt(2)
    rx.Set(reflect.ValueOf(3))
    // rx.SetString("hello")//pannic
    var y interface{}
    ry := reflect.ValueOf(&y).Elem()
    ry.Set(reflect.ValueOf(3))
    ry.Set(reflect.ValueOf("hello"))
    fmt.Println(y)
    // ry.SetInt(2) //panic
}

func addressable_main3() {
    stdout := reflect.ValueOf(os.Stdout).Elem()
    fmt.Println(stdout.Type())
    fd := stdout.FieldByName("fd")
    fmt.Println(fd.Int())

}

获取结构体方法的名称

由下代码可以看到v作为reflect.Value类型的变量
可以通过v.Method(i).Type().String()v.Type().Method(i).Name()

func PrintMethodName(x interface{}) {
    v := reflect.ValueOf(x)
    vt := v.Type()
    fmt.Printf("type %s \n", vt)

    for i := 0; i < v.NumMethod(); i++ {
        methType := v.Method(i).Type()
        fmt.Println("func (%s) :%s :%s\n", vt, vt.Method(i).Name,
            strings.TrimPrefix(methType.String(), "func"))
    }
}

有疑问加站长微信联系(非本文作者)

本文来自:CSDN博客

感谢作者:KingEasternSun

查看原文:《The.Go.Programming.Language.2015.11》之 reflect

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

942 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传