go的反射

反射引出

结构体的tag字段

利用反射机制编写函数的适配器(桥连接)

反射基本

1)反射可以在运动时动态获取变量的各种信息,比如变量的类型(type)类别(kind)

2)如果是结构体变量,还可以获取到结构体本身的信息(包括结构体的字段,方法)

3)通过反射,可以修改变量的值,可以调用关联的方法

4)使用反射,要用包 reflect

反射示意图

 

反射重要的函数和概念

1)reflect.TypeOf(变量名),获取变量的类型返回reflect.Type类型

2)reflect.Value(变量名),获取变量的值,返回reflect.Value类型,reflect.Value是一个结构体

3)变量 空接口 reflect.Value是可以相互转换的,实际开发中会经常用到

eg:

相互转换

 之间的关系

 相互转换案例

package main

import (
    "fmt"
    "reflect"
)

//演示反射
func reflectTest01(a interface{}) {
    //通过反射获取传入的变量, type,king,值
    // 1.获取type
    rtype := reflect.TypeOf(a)
    fmt.Println(rtype)

    // 获取到reflect.Value()
    rVal := reflect.ValueOf(a)
    fmt.Println(rVal)

    rrVal := reflect.TypeOf(rVal)
    fmt.Println(rrVal)

    n1 := 20 + rVal.Int()
    fmt.Println(n1)

    //将rval转回interface
    iv := rVal.Interface()
    //将interface{}通过断言转回需要的类型
    num := iv.(int)
    fmt.Printf("%T", num)
}

type Student struct {
    Name string
    Age  int
}

//对结构体的反射
func reflectTest02(a interface{}) {
    // 1.获取type
    rtype := reflect.TypeOf(a)
    fmt.Println(rtype)

    // 获取到reflect.Value()
    rVal := reflect.ValueOf(a)
    fmt.Println(rVal)
    
    //获取对应的kind
    //rVal.Kind()
    //rtype.Kind()
    fmt.Printf("kind=%v,kind=%v",rVal.Kind(),rtype.Kind())
    
    //将rval转回interface
    iv := rVal.Interface()
    fmt.Printf("%T,,,%v\n", iv, iv)
    //将interface{}通过断言转回需要的类型
    //使用一个待检测的switch的断言形式
    stu, ok := iv.(Student)
    if ok {
        fmt.Printf("%v", stu.Name)
    }

}
func main() {
    num := 100
    reflectTest01(num)

    fmt.Println("_____________________________________")
    stu := Student{
        Name: "tom",
        Age:  100,
    }
    reflectTest02(stu)
}

反射细节和注意

1)reflect.Value.Kind()获取变量类别返回是一个常量

2)type是类型,Kind是类别。tpye和Kind可能相通也可能不相同

eg:

var num int=10 type=int Kind=int

var stu Student stu的Type是包名(pkg1).Student,King是struct

3)通过反射可以让变量在interface()和reflect.Value之间相互转换,这点在前面有示意图:

变量《------------》interface{}《----------》reflect.Value

 

否则,报错

 5)反射修改变量值要使用reflect.Value.Elem()方法

package main

import (
    "fmt"
    "reflect"
)

func reflect01(a interface{}) {
    rVal := reflect.ValueOf(a)
    //传入地址的话,rVal是一个指针
    fmt.Println(rVal.Kind())
    // Elem返回v持有的接口保管的值的Value封装,或者v持有的指针指向的值的Value封装
    rVal.Elem().SetInt(100)

}
func main() {
    num := 1
    reflect01(&num)
    fmt.Println(num)

    //可以这样理解rVal.Elem()
    num1 := 9
    ptr := &num1
    num2 := *ptr
    fmt.Println(num2)
}

反射最佳实践

package main

import (
    "fmt"
    "reflect"
)

type Monster struct {
    Name  string  `json:"name"`
    Age   int     `json:"age"`
    Score float64 `json:"score"`
    Sex   string  `json:"sex"`
}

func (m Monster) Print() {
    fmt.Println("-----start-----")
    fmt.Println(m)
    fmt.Println("----- end------")
}

func (m Monster) GetSum(n1 int, n2 int) int {
    return n1 + n2
}

func (m *Monster) Set(name string, age int, score float64, sex string) {
    m.Name = name
    m.Age = age
    m.Score = score
    m.Sex = sex
}

func TestStruct(a interface{}) {
    //获取reflect.Type类型
    typ := reflect.TypeOf(a)
    //获取reflect.Value类型
    val := reflect.ValueOf(a)
    // 获取到a对应的类别
    kd := val.Kind()
    if kd != reflect.Struct {
        fmt.Println("传入参数不为结构体,已自动退出")
        return
    }
    //获取该结构体题的字段数
    num := val.NumField()
    fmt.Println("该结构体有", num, "个字段")
    //循环输出字段
    for i := 0; i < num; i++ {

        fmt.Printf("字段:%v,值为:%v,", i, val.Field(i))
        tagval := typ.Field(i).Tag.Get("json")
        if tagval != "" {
            fmt.Printf("tag标签为%v,\n", tagval)
        } else {
            fmt.Println()
        }
    }
    numMethod := val.NumMethod()
    fmt.Println("该结构体有", numMethod, "个方法")
    // 获取到第二个方法,并调用
    //方法排序是按照函数名字母(ASCII码)进行的排序
    val.Method(1).Call(nil)
    // 调用结构体的第一个方法Method(0)
    var params []reflect.Value
    params = append(params, reflect.ValueOf(20))
    params = append(params, reflect.ValueOf(72))
    res := val.Method(0).Call(params)
    fmt.Println(res[0].Int())
}
func main() {
    mon := &Monster{
        Name:  "孙悟空",
        Age:   1000,
        Score: 100.2,
        Sex:   "男",
    }
    TestStruct(mon)
}

package main

import (
    "fmt"
    "reflect"
)

type Monster struct {
    Name  string  `json:"name"`
    Age   int     `json:"age"`
    Score float64 `json:"score"`
    Sex   string  `json:"sex"`
}

func (m *Monster) Print() {
    fmt.Println("-----start-----")
    fmt.Println(m)
    fmt.Println("----- end------")
}

func (m *Monster) GetSum(n1 int, n2 int) int {
    return n1 + n2
}

func (m *Monster) Set(name string, age int, score float64, sex string) {
    m.Name = name
    m.Age = age
    m.Score = score
    m.Sex = sex
}

func TestStruct(a interface{}) {
    //获取reflect.Type类型
    typ := reflect.TypeOf(a)
    //获取reflect.Value类型
    val := reflect.ValueOf(a)
    // 获取到a对应的类别
    kd := val.Kind()
    if kd != reflect.Ptr && val.Elem().Kind() == reflect.Struct {
        fmt.Println("传入参数不为结构体,已自动退出")
        return
    }
    //获取该结构体题的字段数
    num := val.Elem().NumField()
    fmt.Println("该结构体有", num, "个字段")
    //修改值
    val.Elem().Field(0).SetString("刘广硕")
    //循环输出字段
    for i := 0; i < num; i++ {

        fmt.Printf("字段:%v,值为:%v,", i, val.Elem().Field(i))
        tagval := typ.Elem().Field(i).Tag.Get("json")
        if tagval != "" {
            fmt.Printf("tag标签为%v,\n", tagval)
        } else {
            fmt.Println()
        }
    }
    numMethod := val.NumMethod()
    fmt.Println("该结构体有", numMethod, "个方法")
    // 获取到第二个方法,并调用
    //方法排序是按照函数名字母(ASCII码)进行的排序
    val.Method(1).Call(nil)
    // 调用结构体的第一个方法Method(0)
    var params []reflect.Value
    params = append(params, reflect.ValueOf(20))
    params = append(params, reflect.ValueOf(72))
    res := val.Method(0).Call(params)
    fmt.Println(res[0].Int())
}
func main() {
    mon := &Monster{
        Name:  "孙悟空",
        Age:   1000,
        Score: 100.2,
        Sex:   "男",
    }
    TestStruct(mon)
}

package main

import (
    "reflect"
    "testing"
)

func TestReflectFunc(t *testing.T) {
    call1 := func(v1 int, v2 int) {
        t.Log(v1, v2)
    }
    call2 := func(v1 int, v2 int, s string) {
        t.Log(v1, v2, s)
    }
    var (
        function reflect.Value
        invalue  []reflect.Value
        n        int
    )
    bridge := func(call interface{}, args ...interface{}) {
        n = len(args)
        invalue = make([]reflect.Value, n)
        for i := 0; i < n; i++ {
            invalue[i] = reflect.ValueOf(args[i])
        }
        function = reflect.ValueOf(call)
        function.Call(invalue)
    }
    bridge(call1, 1, 2)
    bridge(call2, 1, 2, "test2")
}
package main

import (
    "reflect"
    "testing"
)

type user struct {
    UserId string
    Name   string
}

func TestReflectStruct(t *testing.T) {
    var (
        model *user
        st    reflect.Type
        elem  reflect.Value
    )
    st = reflect.TypeOf(model)                  //获取类型*user
    t.Log("reflect.TypeOf", st.Kind().String()) //ptr
    st = st.Elem()                              //st指向的类型
    elem = reflect.New(st)
    t.Log("reflect.New", elem.Kind().String()) //ptr
    t.Log("reflect.New.Elem", elem.Elem().Kind().String())
    //model就是创建的user结构体变量
    model = elem.Interface().(*user) //model是*user它的指向和elem是一样的
    elem = elem.Elem()               //取得elem指向的值
    elem.FieldByName("UserId").SetString("12345678")
    elem.FieldByName("Name").SetString("nickname")
    t.Log("model model.Name", model, model.Name)

}
package main

import (
    "fmt"
    "math/rand"
    "reflect"
    "time"
)

type Cal struct {
    Num1 int
    Num2 int
}

func (c *Cal) GetSum(name string) string {
    return fmt.Sprintf("%v完成了减法运算,%v - %v = %v", name, c.Num1, c.Num2, c.Num1-c.Num2)
}

func TestCal(c interface{}) {
    // typ := reflect.TypeOf(c)
    val := reflect.ValueOf(c)
    num := val.Elem().NumField()
    rand.Seed(time.Now().Unix())
    for i := 0; i < num; i++ {
        val.Elem().Field(i).SetInt(int64(rand.Intn(100)))
    }
    var params []reflect.Value
    params = append(params, reflect.ValueOf("tom"))
    res := val.Method(0).Call(params)
    fmt.Println(res)
}
func main() {
    c := &Cal{}
    TestCal(c)
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值