1.判断函数变量是否否和标准
2.验证接口值是否合理如(是否为空,传入的字段是否合规)
3.获取变量的类型进行断言等操作
在Go语言的反射机制中,任何接口值都由是一个具体类型和具体类型的值两部分组成的(我们在上一篇接口的博客中有介绍相关概念)。 在Go语言中反射的相关功能由内置的reflect包提供,任意接口值在反射中都可以理解为由reflect.Type和reflect.Value两部分组成,并且reflect包提供了reflect.TypeOf和reflect.ValueOf两个函数来获取任意对象的Value和Type。
reflect.TypeOf() 获取类型信息,返回 Type 类型;
reflect.ValueOf() 获取数据信息,返回 Value 类型。
反射中值的可设置性,可以用 CanSet 方法来判断值是否可以设置。在 Go 中,函数参数的传递都是值拷贝,在反射中要修改值,必须传递指针,并且用 Elem() 方法获取指针的值,然后进行修改。
在 type MyInt int 里,v.Kind() 与 v.Type() 返回了不同的类型值,Kind()返回的是 int,Type() 返回的是 MyInt。在 Go 中,可以用 type 关键字定义自定义类型,Kind() 方法返回底层类型。比如还有结构体,指针等类型用 type 定义的,那么 Kind() 方法就可以获取这些类型的底层类型。
package mainimport ( "fmt" "reflect")type Userinfo struct { Age int `id:"iloveyou" num:"222"` //tag标签信息 UserName string}func GetReflickInfo(i interface{}) { vl := reflect.ValueOf(i) //nii := 200 fmt.Println("kind ======", vl.Kind()) if vl.Kind() == reflect.Ptr { //如是指针类型,先取值 vl = vl.Elem() //Elem方法就是取值操作 } vlt := vl.Type() //获取具体类型,如自定义结构体的类型 fmt.Println("kind ======type===", vl.Kind(), vlt) if vl.Kind() != reflect.Struct { fmt.Println("类型:", vlt, " 名字:", vlt.Name(), " 数值:", vl) //如是整数种类,又可以修改,CanSet属性为true,则进行修改。 if vl.Kind() == reflect.Int || vl.Kind() == reflect.Int64 && vl.CanSet() { vl.SetInt(100) //reflect.New(vlt)是创建了一个vlt类型的指针变量。 ni := reflect.New(vlt) //创建后的ni是reflect.Value对象,需要通过ValueOf来赋值 ni = reflect.ValueOf(222) fmt.Println("修改后int数值:", vl, "新建数值:", ni) } //如是浮点数种类,又可以修改,CanSet属性为true,则进行修改。 //可设置性检查:vl.CanSet() 是一个方法,用于确认vl的值是否可以被修改。在Go中,不是所有的反射值都能被设置,比如函数参数或者某些静态类型就不能。如果vl的值可以被改变,CanSet()将返回true。 if vl.Kind() == reflect.Float32 || vl.Kind() == reflect.Float64 && vl.CanSet() { vl.SetFloat(100.11) //调用vl.SetFloat(100.11)方法将变量vl的值设置为100.11。 fmt.Println("修改后float数值:", vl) } } else { fmt.Println("结构体类型:", vlt, " 名字:", vlt.Name()) for i := 0; i < vl.NumField(); i++ { //vl是具体的值,这里vl.Field(i)就是枚举出每一个成员的值 //vlt是获取的类型,vlt.Field(i).Name和.Type是枚举出每一个成员的名字和类型 //也可以使用FieldByName,从指定的成员名获取具体值,vlret:= vl.FieldByName(vlt.Field(i).Name) fmt.Println("成员名:", vlt.Field(i).Name, " 类型:", vlt.Field(i).Type, " 数值:", vl.Field(i)) //如是字符串种类,又可以修改,CanSet属性为true,则进行修改。 if vl.Field(i).Kind() == reflect.String && vl.Field(i).CanSet() { vl.Field(i).SetString("new str") fmt.Println("string成员修改后数值:", vl.Field(i)) } //而tag标签信息都是静态的,无须实例化结构体,通过类型vlt可以获取到。 //这句vlt.Field(i).Tag.Lookup("id")就是枚举出每一个成员的tag标签,看里面是否有id这个key,并返回它的value值 if idtag, b := vlt.Field(i).Tag.Lookup("id"); b { fmt.Println("tag id=", idtag) } if numtag, b := vlt.Field(i).Tag.Lookup("num"); b { fmt.Println("tag num=", numtag) } } }}func main() { var price float64 = 3.14 var age int64 = 5 bd := Userinfo{100, "andy"} ns := struct { //定义一个无名结构体 id int addr string }{2, "aa"} GetReflickInfo(price) GetReflickInfo(&age) //把变量地址传递,所以可以修改。 GetReflickInfo(&bd) //把结构体地址传递,所以可以修改。 fmt.Println(bd) //打印出修改后的结构体变量 GetReflickInfo(ns)}
本文链接:http://www.28at.com/showinfo-26-87989-0.html一篇学会Go中reflect反射的详细用法
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com
上一篇: 深入理解分布式锁:原理、应用与挑战