golang反射

反射

基本介绍

  1. 反射可以在运行时动态获取变量的各种信息,比如变量的类型(type)、类别(kind)
  2. 如果是结构体变量,可以获取到结构体本身的信息(包括结构体的字段、方法)
  3. 通过反射,可以修改变量的值,可以调用关联的方法
  4. 使用反射,需要import(“reflect”)
  5. 示意图
    在这里插入图片描述

应用场景

  1. reflect.TypeOf(变量名) 获取变量的类型,返回reflect.Type类型
  2. reflect.ValueOf(变量名)获取变量的值,返回reflect.Value 是一个结构体类型,通过reflect.Value,可以获取该变量的很多信息
  3. 变量、interface{} 和 reflect.Value 是可以相互转换的,这点在实际开发中经常会用到

基本使用


// 演示反射
func reflectTest01(b interface{}) {
	rTyp := reflect.TypeOf(b)
	fmt.Println("TypeOf", rTyp)
	fmt.Printf("TypeOf Type %T \n", rTyp)
	value := reflect.ValueOf(b)
	fmt.Println("ValueOf", value)
	fmt.Printf("ValueOf %T\n", value)

	fmt.Println(value.Int() + 13)

	// 将 rVal 转成interface{}
	iv := value.Interface()
	// 将 any 断言
	num2 := iv.(int)
	fmt.Println(num2)

}

func TestReflect(t *testing.T) {
	var num int = 100
	reflectTest01(num)
}

结构体


// 演示反射
func reflectTest01(stu Student) {
	stuType := reflect.TypeOf(stu)
	fmt.Println("stuType", stuType)
	fmt.Println("stuType Kind", stuType.Kind())
	stuValue := reflect.ValueOf(stu)
	fmt.Println("stuValue", stuValue)
	fmt.Println("stuValue Kind", stuValue.Kind())

	stuIv := stuValue.Interface()
	fmt.Printf("接口 类型 %T \n", stuIv)

	student, ok := stuIv.(Student)
	if ok {
		fmt.Printf("接口 类型 %T \n", student)
	}

}

type Student struct {
	Name string
	Age  int
}

func TestReflect(t *testing.T) {
	student := Student{
		"tom", 13,
	}
	reflectTest01(student)
}

注意

  1. reflect.Value.Kind 获取变量的类别,返回的是一个产量
  2. Type 是类型 Kind是类别,Type和Kind可能相同,可能不同
    比如:int Type :int ; Kind:int
    Student Type:Student ; Kind:struct
  3. 通过反射可以在让变量在 interface{} 和 Reflect.Value 之间相互转换
  4. 使用反射的方式来获取变量的值(并返回对应的类型),要求数据类型匹配,否则panic
  5. 通过反射修改变量,注意当使用setXxx方法来设置需要通过对应的指针来完成,同时需要使用reflect.Value.Elem
func TestReflect(t *testing.T) {
	i := 10
	iValue := reflect.ValueOf(&i)
	// 获取指针进行修改值
	iValue.Elem().SetInt(20)
	fmt.Println(i)
}

练习

func TestReflect(t *testing.T) {
	var v float64 = 1.2
	value := reflect.ValueOf(v)
	vType := value.Type()
	vKind := value.Kind()
	fmt.Println(vType, vKind, value)

	fv, ok := value.Interface().(float64)
	if ok {
		fmt.Printf("FV 的值 %v 类型 %T \n", fv, fv)
	}
}

最佳实践

遍历结构体的方法,调用接头体的方法,获取结构体的标签

func TestReflect(t *testing.T) {
	m := Monster{
		Name:  "黄书狼",
		Age:   400,
		Score: 30.8,
	}
	mType := reflect.TypeOf(m)
	mValue := reflect.ValueOf(m)

	if mValue.Kind() != reflect.Struct {
		fmt.Println("expect struct")
		return
	}
	num := mValue.NumField()
	fmt.Printf("struct has %d field \n", num)
	for i := 0; i < num; i++ {
		fmt.Printf("字段 %d 值为%v\n", i, mValue.Field(i))
		// 获取struct标签,注意需要通过reflect.Type 来获取tag标签的值
		tagVal := mType.Field(i).Tag.Get("json")
		if tagVal != "" {
			fmt.Printf("字段 %d : tag为%v\n", i, tagVal)
		}
	}
	methodNum := mValue.NumMethod()
	fmt.Printf("struct has %d method \n", methodNum)

	mValue.Method(1).Call(nil) // 按照名字的ASC码排序
	//mValue.MethodByName("Print").Call(nil)
	var params []reflect.Value
	params = append(params, reflect.ValueOf(10))
	params = append(params, reflect.ValueOf(40))
	res := mValue.Method(0).Call(params)
	fmt.Println("res ", res[0].Int())
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值