golang 反射 reflect demo

柔情痞子 提交于 2020-08-06 14:03:05
package main

import (
    "fmt"
    "go/ast"
    "reflect"
)

type Member struct {
    Id     int    `json:"id" orm:"member_id"`
    Name   string `json:"name"`
    status bool
}

func (m *Member) SetStatus(s bool) {
    m.status = s
}

func (m *Member) GetStatus() bool {
    return m.status
}

func (m Member) String() string {
    return fmt.Sprintf("id: %d, name: %s", m.Id, m.Name)
}

// 如果是值传递那么反射获取的对象将不能修改此值,否则 panic
func Parse(v interface{}) {
    // 获取 v 的变量值,如果是地址传递获取的是指针,值传递则为变量值
    rValue := reflect.ValueOf(v)
    // 判断是否为一个指针,如果是指针就通过 Elem() 获取指针指向的变量值
    rValue = reflect.Indirect(rValue)
    // 获取 v 的变量类型
    rType := rValue.Type()
    // rType := reflect.TypeOf(v)

    switch rType.Kind() {
    case reflect.Struct:
        // 遍历结构体字段
        for i := 0; i < rValue.NumField(); i++ {
            field := rType.Field(i)
            // 忽略匿名字段和私有字段
            if !field.Anonymous && ast.IsExported(field.Name) {
                // 获取结构体字段的 interface{} 变量
                fmt.Println(rValue.Field(i).Interface())
                // 对于值传递的结构体使用 Addr() 获取结构体字段 *interface{} 变量会报错
                fmt.Println(reflect.TypeOf(rValue.Field(i).Addr().Interface()))
                // 获取字段 tag
                fmt.Println(rType.Field(i).Tag.Get("json"))
            }
        }

        // 根据字段名获取字段 interface{}
        fmt.Println(rValue.FieldByName("Name").Interface())

        // 获取非指针方法数量,案例中的 Member 的 String 方法
        fmt.Println(rValue.NumMethod())
        // 获取所有方法数量
        fmt.Println(rValue.Addr().NumMethod())
        // 遍历结构体方法

        rValue.Addr().MethodByName("SetStatus").Call([]reflect.Value{reflect.ValueOf(true)})
        fmt.Println(rValue.Addr().MethodByName("GetStatus").Call(nil))
        // 排序默认是按照函数名的排序(ASCII 码)
        fmt.Println(rValue.Addr().Method(2).Call(nil))
        fmt.Println(rValue.Method(0).Call(nil))

        // 创建一个新反射对象
        fmt.Println(reflect.New(rType).Elem().FieldByName("Id"))
    case reflect.Func:
        num := 2
        argv := make([]reflect.Value, rType.NumIn())
        for i := range argv {
            if rType.In(i).Kind() == reflect.Int {
                argv[i] = reflect.ValueOf(num)
            }
        }
        result := rValue.Call(argv)
        if len(result) == 1 {
            fmt.Println(result[0].Int())
        }
    case reflect.Int:
        // 修改值
        rValue.SetInt(127)
        // 从反射对象获取 interface{} 变量
        rIntf := rValue.Interface()
        // 根据 interface{} 进行类型断言
        if num, ok := rIntf.(*int); ok {
            fmt.Println(num)
        }
    case reflect.Slice:
        // 切片类型
        fmt.Println(rType.Kind())
        // 切片内元素类型
        // Elem() 作用是返回接口 v 包含的值或 v 指向的指针
        fmt.Println(rType.Elem().Kind())
    }
}

func Add(a, b int) int {
    return a + b
}

func main() {
    m := &Member{
        Id:   23,
        Name: "jack",
    }
    Parse(m)
    fmt.Println(m.GetStatus())

    // 函数调用
    Parse(Add)

    num := 6
    // 如果为值传递修改时会 panic
    Parse(&num)
    fmt.Println(num)

    var ms []Member
    Parse(&ms)
}
/*
23
*int
id
jack
*string
name
jack
1
3
[<bool Value>]
[id: 23, name: jack]
[id: 23, name: jack]
0
true
4
127
slice
struct
*/
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!