Go反射编程

什么是反射编程

//反射编程
//reflect.TypeOf返回类型(reflect.Type)
//reflect.ValueOf返回值(reflect.Value)
//可以从reflect.Value获得类型 可以通过kind来判断类型
//拿到一个instance 可以反射出它的类型和它的值

//go 用常量代表一个类型枚举,判断类型

//使用反射做一些灵活的程序 反射可以灵活的做一些万能程序
//以字符串 字符的方式,调用类型中的某一个方法
//访问类型中的某个成员 传入方法名字或者变量名字来访问
//按名字访问结构的成员 reflect.ValueOf(*e).FieldByName("Name")
//按名字访问结构的方法 reflect.ValueOf(e).MethodByName("UpdateAge").call([]reflect.Value{reflect.ValueOf(1)})

Reflect.Type和Reflect.Value都有FieldByName方法,注意区别

演示代码


import (
	"fmt"
	"reflect"
	"testing"
)

func TestTypeAndValue(t *testing.T)  {
	var f int64 = 10
	t.Log(reflect.TypeOf(f),reflect.ValueOf(f))
	t.Log(reflect.ValueOf(f).Type())
}

func CheckType(v interface{})  {
	//空接口可以接受所有类型
	t := reflect.TypeOf(v)
	switch t.Kind() {
	case reflect.Float32,reflect.Float64:
		fmt.Println("Float")
	case reflect.Int,reflect.Int32,reflect.Int64:
		fmt.Println("Interger")
	default:
		fmt.Println("Unknow",t)
	}
}

func TestBasicType(t * testing.T)  {
	var f float64 = 12
	CheckType(f)
}

func TestDeepEqual(t *testing.T)  {

}

type Employee struct {
	EmployeeID string
	Name string "format:'normal'"	//struct Tag
	Age int
}

func (e *Employee) UpdateAge(newVal int)  {
	e.Age = newVal
}

type Customer struct {
	CookieID string
	Name string
	Age int
}

func TestInvokeByName(t *testing.T)  {
	e := &Employee{"1","Mike",30}
	//按照名字获取成员 通过反射的方式 直接返回了名字的值
	t.Logf("Name value(%[1]v),Type(%[1]T)",reflect.ValueOf(*e).FieldByName("Name"))
	if nameField,ok := reflect.TypeOf(*e).FieldByName("Name");!ok{
		//返回两个值 ok代表 有没有这个值
		t.Error("Failed to get 'Name' field")
	} else {
		t.Log("Tag:format",nameField.Tag.Get("format"))
	}

	reflect.ValueOf(e).MethodByName("UpdateAge").Call([]reflect.Value{reflect.ValueOf(1)})
	t.Log("Update Age:",e)
}
//名字和结构体的对应 都是通过 structTag

反射的万能编程

package ch38

import (
	"errors"
	"reflect"
	"testing"
)

type Employee struct {
	Employee string
	Name string
	Age int
}
type Customer struct {
	CookieID string
	Name string
	Age int
}

func (e *Employee) UpdateAge(newVal int)  {
	e.Age = newVal
}

// 切片和map只能和空集进行比较
func TestDeepEqual(t *testing.T)  {
	a := map[int]string{1:"one",2:"two",3:"three"}
	b := map[int]string{1:"one",2:"two",3:"three"}

	//t.Log(a == b)
	t.Log(reflect.DeepEqual(a,b))

	s1 := []int{1,2,3}
	s2 := []int{2,4,6}
	s3 := []int{1,4,6}
	//t.Log(s1 == s2)
	t.Log(reflect.DeepEqual(s1,s2))
	t.Log(reflect.DeepEqual(s2,s3))
}

//关于反射的要求
//提高了程序的灵活性 降低了程序的可读性 降低了程序的性能
//构建一个 通用的填充方法
//公共方法解决不同结构体的填充
func fillBySettings(st interface{},settings map[string]interface{}) error {
	//func (v value) Elem() Value
	//Elem returns the value that the interface{} v contains or that the pointer
	//It panics if v's Kind is not
	if reflect.TypeOf(st).Kind() != reflect.Ptr{
		//elem()获取指针指向的值
		if reflect.TypeOf(st).Elem().Kind() != reflect.Struct{
			//判断是不是结构

			//如果不满足以上条件 不是指针也不是结构 就会返回
			return errors.New("the first param should be a pointer to the struct type")
		}
	}
	if settings == nil{
		return errors.New("settings is nil")
	}

	var(
		field reflect.StructField
		ok bool
	)

	//传入的是一个指针类型 FieldByName只能从结构类型上去获得
	//从指针类型到指针类型指向的结构,需要使用一个Elem()这样的方法处理 获得了指针指向的结构
	//便利存入的Map k代表类型名字 观测本程序当中是否是Field的名字
	for k,v := range settings{
		if field,ok = (reflect.ValueOf(st)).Elem().Type().FieldByName(k);!ok{
			continue
		}
		//Map和field的类型一致
		if field.Type == reflect.TypeOf(v){
			vstr := reflect.ValueOf(st)
			vstr = vstr.Elem()
			//满足条件后 就设置 Value部 分
			vstr.FieldByName(k).Set(reflect.ValueOf(v))
		}
	}
		return nil
}

func TestFillNameAndAge(t *testing.T)  {
	settings := map[string]interface{}{"Name":"Mike","Age":40}
	e := Employee{}
	if err := fillBySettings(&e,settings);err != nil{
		t.Fatal(err)
	}
	t.Log(e)
	c:=new(Customer)
	if err := fillBySettings(c,settings);err != nil{
		t.Fatal(err)
	}
	t.Log(*c)
}
//和配置有关的程序 需要灵活性的程序 我们都可以使用反射完成
//在性能特别高的情况下 我们要注意 可读性疯狂下降 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值