Golang 基础库之Reflect包

Reflect

​ reflect包实现了运行时反射,允许程序操作任意类型的对象。典型用法是用静态类型interface{}保存一个值,通过调用TypeOf获取其动态类型信息,该函数返回一个Type类型值。调用ValueOf函数返回一个Value类型值,该值代表运行时的数据。Zero接受一个Type类型参数并返回一个代表该类型零值的Value类型值。

1. reflect.TypeOf()

  • info := reflect.TypeOf() :获取任意值的类型对象

  • info.Name():类型名称 表类型 比如type MyFloat64 float64中的MyFloat64 ,或者type T struct 中的T;对于未定义的类型返回空字符串

    • 	// Name returns the type's name within its package for a defined type.
      	// For other (non-defined) types it returns the empty string.
      	Name() string
      
  • info.Kind():种类 基类型 比如type MyFloat64 float64中的float64;或者type T struct 中的struct

    • 	// Kind returns the specific kind of this type.
      	Kind() Kind
      
  • eg:
    func reflect_type(a interface{}) {
    	t := reflect.TypeOf(a)
    	fmt.Println("Type:", t)
    	n := t.Name()
    	fmt.Println("Type Name:", n)
    	//kind ()可以获取具体类型
    	k := t.Kind()
    	fmt.Println("Kind:", k)
    	switch k {
    	case reflect.Float64:
    		fmt.Println("a :", reflect.Float64)
    	case reflect.String:
    		fmt.Println("a :", reflect.String)
    	case reflect.Ptr:
    		fmt.Println("a :", reflect.Ptr)
    	default:
    		fmt.Println("kind illegal")
    	}
    }
    
    type MyFloat64 float64
    type People struct {
    }
    func main() {
    	var a MyFloat64 = 3.14
    	reflect_type(a)
    	var zhangsan People = People{}
    	reflect_type(zhangsan)
    }
    
    //结果:
    Type: main.MyFloat64
    Type Name: MyFloat64
    Kind: float64
    a : float64
    
    
    Type: main.People
    Type Name: People
    Kind: struct
    a : struct
    

2. reflect.ValueOf()

  • v :=reflect.ValueOf() :获取原始值的值信息

  • kind := v.Kind():种类 基类型 比如type MyFloat64 float64中的float64;或者type T struct 中的struct

  • v.Int(): 原始值 类型必须对应才能取到原值,所以通常会先判断kind

  • 通过反射设置变量的值:

    • 先通过v:=reflect.ValueOf(a)取到原值信息
    • 然后通过 v.Elem().Kind()判断类型
    • 最后通过v.Elem().SetFloat(7.9)修改原值
    • 注意:修改反射值时的a参数必须是原值的指针或地址;否则报错:panic: reflect: reflect.Value.SetFloat using unaddressable value
  • func reflect_set_value(a interface{}) {
    	v := reflect.ValueOf(a)
    	k := v.Kind()
    	switch k {
    	case reflect.Float64:
    		v.SetFloat(6.9)
    		fmt.Println("a is:", v.Float())
    	case reflect.Ptr:
    		v.Elem().SetFloat(7.9)
    		fmt.Println("case:", v.Elem().Float())
    		//地址
    		fmt.Println("addr:", unsafe.Pointer(v.Pointer()))
    	}
    }
    
    func main() {
    	var a MyFloat64 = 3.14
    	reflect_set_value(&a)
    	fmt.Println("main a:", a)
    	fmt.Println("main &a:", &a)
    }
    
    //结果
    case: 7.9
    addr: 0xc000014088
    main a: 7.9
    main &a: 0xc000014088
    

3. 结构体反射

  • reflect.TypeOf()获得反射对象信息后,如果它的类型是结构体,可以通过反射值对象(reflect.TypeOf)的 NumField()和 Field()方法获得结构体成员的详细信息

  • t := reflect.TypeOf(u)

    • t.NumField():获取结构体字段个数

    • f:=t.Field(0) :获取结构体第一个字段

      • f.Name:字段名
      • f.Type:字段类型
      • f.Tag:字段标签
    • f:=t.FieldByName(“Age”):获取对应字段Age的信息

      • f.Name:字段名
      • f.Type:字段类型
      • f.Tag:字段标签
    • t.NumMetod():获取方法个数

    • f:=t.Method(0):和结构体的方法声明顺序没有关系,和结构体方法名的ASCII有关系

      • f.Name:方法名
      • f.Type:方法类型
    • f:=t.MethodByName(“HelloA”):获取结构体指定方法信息;未找到对应方法返回零值(reflect.Value{}) 。

      • // MethodByName returns a function value corresponding to the method
        // of v with the given name.
        // The arguments to a Call on the returned function should not include
        // a receiver; the returned function will always use v as the receiver.
        // It returns the zero Value if no method was found.
        func (v Value) MethodByName(name string) Value 
        
      • f.Name:方法名

      • f.Type:方法类型

      • f.Func.Call(v):调用方法;

        • Call(v):v为参数切片,类型[]reflect.Value,例如:[]reflect.Value{reflect.ValueOf(1), reflect.ValueOf(“s1”)
        • 通过TypeOf反射对象调用方法时,v的list中,第一个参数必须是接收器类型的实例[]reflect.Value{reflect.ValueOf(User{}), reflect.ValueOf(1), reflect.ValueOf(“s1”)}
  • t:=reflect.ValueOf(u)

    • t.MethodByName(“HelloA”).Call(v):调用HelloA方法
    • t.Method(0).Call(v):执行方法,和结构体的方法顺序没有关系,和结构体方法的ASCII有关系
      • Call(v):v为参数切片,类型[]reflect.Value,例如:[]reflect.Value{reflect.ValueOf(1), reflect.ValueOf(“s1”)
      • 注意 通过ValueOf反射出的对象调用 方法时,v的参数列表第一个元素是对应方法的参数,而不是接收器实例
//结构体反射
func (u User) HelloB(v int, s string) {
	fmt.Println("Hello B: int:", v, "string:", s)
}
func (u User) HelloA() {
	fmt.Println("Hello A")
}

func reflect_fun(a interface{}) {
	t := reflect.TypeOf(a)
	fmt.Println("Type:", t)
	n := t.Name()
	fmt.Println("Name:", n)

	v := reflect.ValueOf(a)
	fmt.Printf("%#v \n", v)
	//t.NumField()取结构体字段个数
	for i := 0; i < t.NumField(); i++ {
		//取每个字段 Name Type Tag
		f := t.Field(i)
		fmt.Println("f(", i, "): Name:", f.Name, " Type:", f.Type, " Tag(json):", f.Tag.Get("json"), " Tag(db):", f.Tag.Get("db"))
		//获取字段的值信息
		//Interfance():获取字段对应的值
		val := v.Field(i).Interface()
		fmt.Println("val:", val)
	}

	fmt.Println("==========================遍历方法================================")
	for i := 0; i < t.NumMethod(); i++ {
		//方法的顺序与方法名的ASCII排序有关
		m := t.Method(i)
		fmt.Println("m(", i, ").Name:", m.Name, " Type:", m.Type)
	}
	fmt.Println("==========================取指定方法信息================================")
	f, _ := t.MethodByName("HelloB")
	fmt.Println("HelloB.Name:", f.Name, " Type:", f.Type)
	f.Func.Call([]reflect.Value{reflect.ValueOf(User{}), reflect.ValueOf(1), reflect.ValueOf("s1")})

	fmt.Println("==========================方法信息调用================================")
	v.MethodByName("HelloA").Call(nil)
	v.MethodByName("HelloB").Call([]reflect.Value{reflect.ValueOf(2), reflect.ValueOf("s2")})
	reflect.ValueOf(User{}).MethodByName("HelloB").Call([]reflect.Value{reflect.ValueOf(3), reflect.ValueOf("s3")})

	if v.MethodByName("HelloC") == (reflect.Value{}) {
		fmt.Println("HelloC not found")
	}
}

func main() {
	u := User{
		Id:   1,
		Age:  20,
		Name: "张三",
	}
	reflect_fun(u)
}


//结果
Type: main.User
Name: User
main.User{Id:1, Age:20, Name:"张三"} 
f( 0 ): Name: Id  Type: int  Tag(json): id  Tag(db): db1
val: 1
f( 1 ): Name: Age  Type: int  Tag(json): age  Tag(db): db2
val: 20
f( 2 ): Name: Name  Type: string  Tag(json): name  Tag(db): 
val: 张三
==========================遍历方法================================
m( 0 ).Name: HelloA  Type: func(main.User)
m( 1 ).Name: HelloB  Type: func(main.User, int, string)
==========================取指定方法信息================================
HelloB.Name: HelloB  Type: func(main.User, int, string)
Hello B: int: 1 string: s1
==========================方法信息调用================================
Hello A
Hello B: int: 2 string: s2
Hello B: int: 3 string: s3
HelloC not found
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值