首页 > 其他 > 详细

一、Golang中的反射基本使用

时间:2020-05-19 23:36:00      阅读:67      评论:0      收藏:0      [点我收藏+]

??Go中也提供了反射机制,与Java一样Go的反射也是在运行时获取对象的相关信息,更新对象内部状态;Golang通过反射可以获取对象类型、字段类型与值、调用struct实例方法、更新实例值等;
??Go关于反射相关的对象、函数都在reflect包中最主要的两个为:Type与Value;
??Go提供了下面两个函数,这两个是Go反射的核心;
??reflect.TypeOf 返回目标对象的类型
??reflect.ValueOf 返回值目标对象的值

t:=1
fmt.Println(reflect.TypeOf(t), reflect.ValueOf(t))
输出:int 1

通过反射操作Struct

type Demo struct {
  Id   int
  Name string
}
func (d *Demo) Back() {
    fmt.Println("调用方法 Back")
}
func (d *Demo) Add(a, b int) int {
	return a + b
}

获取结构体中每个成员变量的名称与值:

 d := &Demo{Id: 2, Name: "test"}
 getValue(d)
 输出: Id :  2
      Name :  test

func getValue(v interface{}) {
	t := reflect.TypeOf(v)
	o := reflect.ValueOf(v)
	if t.Kind() == reflect.Ptr {
		t = t.Elem()   //获取类型指针中的类型
	}
	if o.Kind() == reflect.Ptr {
		o = o.Elem()  //获取值地址中的值
	}
	num := t.NumField()  //获取字段个数
	for i := 0; i < num; i++ {
		f := o.Field(i)     //获取字段的值
		fieldName := t.Field(i).Name  //获取字段名称
		switch f.Kind() {
		case reflect.Int:
			fmt.Println(fieldName, ": ", f.Int()) 
		case reflect.String:
			fmt.Println(fieldName, ": ", f.String())
		default:
			fmt.Println("类型不不支持")
		}
	}
}

??对于引用类型使用reflect.TypeOf返回的是该类型的指针,reflect.ValueOf返回的是该类型的值地址;所以对于引用类型都要的相关操作都要调用Elem()函数获取真实的类型与值;
??调用Type或Value对象的NumField函数获取结构体的字段个数
??调用Value对象的Field(i) 可获取字段的值;
??调用Value对象的Kind()函数可获取字段的类型;
??该Value对应于哪种类型调用对应的函数即可获取得到相应的值,如类型不一致将抛出:panic: reflect: call of reflect.Value.Xxx on int Value;

修改结构体中每个成员变量的值:

    d := new(Demo)
    setValue(d)
    fmt.Println(d)
    输出:&{88 Test}

    func setValue(v interface{}) {
	t := reflect.TypeOf(v)
	o := reflect.ValueOf(v)
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	if o.Kind() == reflect.Ptr {
		o = o.Elem()
	}
	num := t.NumField()
	for i := 0; i < num; i++ {
		f := o.Field(i)
		switch f.Kind() {
		case reflect.Int:
			f.SetInt(88)    //往该字段设值
		case reflect.String:
			f.SetString("Test") /往该字段设值
		default:
			fmt.Println("类型不支持")
		}
	}
    }

??修改字段值与获取值一样,类型一定要一致,如不一致将抛异常,如int类型却调用SetString设值:panic: reflect: call of reflect.Value.SetString on int Value;

调用结构体的无参方法:

d := new(Demo)
callMethod(d) 
输出:调用方法 Back

func callMethod(v interface{}) {
	o := reflect.ValueOf(v)
	o.MethodByName("Back").Call(nil)
}

??调用MethodByName根据名称获取方法,Call调用该方法;

调用结构体的有参方法:

d := new(Demo)
callMethodParam (d) 
输出:3

func callMethodParam(p interface{}) {
	o := reflect.ValueOf(p)
	args:=[]reflect.Value{reflect.ValueOf(1), reflect.ValueOf(2)}
	v:= o.MethodByName("Add").Call(args)
	fmt.Println(v[0])
}

??比较常用的方法还有:
??使用名字获取结构体的成员
Refletct.ValueOf(*e).FieldByName(“Name”)
??获取结构体成员的json标记信息
reflect.TypeOf(s) . Field(0).Tag.Get(“key”)

??Golang的反射也遵循Go语言规则,反射无法修改结构体中的私有对象,无法调用私有私有方法,可访问私有成员,修改私有成员将会抛出reflect.flag.mustBeAssignable异常;

技术分享图片

文章首发地址:Solinx
https://mp.weixin.qq.com/s/W0UVbFxMMeXA5HuNNZlK-A

一、Golang中的反射基本使用

原文:https://www.cnblogs.com/softlin/p/12920032.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!