参考 :http://c.biancheng.net/view/4407.html
反射是指在程序运行期对程序本身进行访问和修改的能力,程序在编译时变量被转换为内存地址,变量名不会被编译器写入到可执行部分,在运行程序时程序无法获取自身的信息
举个例子说明啥是反射呢?
就是比如 python getattr 函数类似,通过字段属性名 拿到字段对应的值。
或者 a = "xxx"
js 里面 map.xxx 也可以 map[a]
go 里面什么情况用反射
我现在想通过字段名的 字符串变量,获取结构体对应的字段值, 貌似只能用 xxx_struct.xxx 而不能像 js 里面那样 xxx_struct["xxx"] , 那就只能用 反射了。
go 怎么实现 反射
使用 内置包 reflect
reflect 定义了两个重要的类型 Type 和 Value 任意接口值在反射中都可以理解为由 reflect.Type 和 reflect.Value 两部分组成
reflect 反射 练习
-
反射获取信息 reflect.TypeOf
返回的是 reflect.Type 类型
reflect.Type 对象可以访问任意值的类型信息, 有两个重要的 函数, Name() 返回Type 和 Kind() 返回 Kind 种类
reflect.TypeOf (xxx interface{}).Name() 返回定义
int、string、bool、float32 以及 使用 type 定义的类型名
reflect.TypeOf (xxx interface{}).Kind() 返回定义
int、string、bool、float32 struct func 这种原始的类型名
普通类型获取反射类型
type A struct{}
var a A
reflect.TypeOf(a).Name() // A
reflect.TypeOf( a ).Kind() // struct
指针类型获取 反射类型
reflect.TypeOf(a).Elem().Name()/Kind()
获取结构体的成员类型信息
(只是信息,并不能取到对应的值)
针对结构体,即如果 反射的 Kind() 返回的 是 struct ,那可以通过一下函数,获取它成员的信息
- reflect.TypeOf (xxx interface{}).NumField()
返回结构体成员字段数量
NumField() int
- reflect.TypeOf (xxx interface{}).Field()
返回索引对应的结构体字段的信息
Field(i int) StructField
- reflect.TypeOf (xxx interface{}).FieldByName()
返回字符串对应的结构体字段的信息
FieldByName(name string) (StructField, bool)
- reflect.TypeOf (xxx interface{}).FieldByIndex()
多层成员访问时,根据 []int 提供的每个结构体的字段索引,返回字段的信息
FieldByIndex(index []int) StructField
- reflect.TypeOf (xxx interface{}).FieldByNameFunc()
根据匹配函数匹配需要的字段
FieldByNameFunc(match func(string) bool) (StructField,bool)
说明一下, 上面函数返回为 StructField 对象(Field, FieldByName, FieldByIndex, FieldByNameFunc ),StructField 对象具有以下属性
StructField 对象结构体字段
type StructField struct {
Name string // 字段名
PkgPath string // 字段路径
Type Type // 字段反射类型对象, 字段本身的反射类型对象,类型为
// reflect.Type,可以进一步获取字段的类型信息, 像递归了
Tag StructTag // 字段的结构体标签
Offset uintptr // 字段在结构体中的相对偏移
Index []int // Type.FieldByIndex中的返回的索引值
Anonymous bool // 是否为匿名字段
}
举个例子说明获取结构体的字段信息
func main(){
type girl struct{
name string `json:"nikname"`
age int
high int
}
var a = girl{"小莲", 28, 165}
reflect_type := reflect.TypeOf(a)
fmt.Println( "Name():", reflect_type.Name(), "kind():", reflect_type.Kind())
kind := reflect_type.Kind()
if kind == reflect.Struct{
fmt.Printf("是结构体\n")
// 遍历获取名称, Field 通常和 NumField 以前搭配使用, 遍历结构体, 这
// 里仅获取结构体成员信息,并没有获取值
for i := 0; i < reflect_type.NumField(); i++{
fmt.Printf("index: %v, file name: %v\n", i, reflect_type.Field(i).Name)
}
// 通过字段名字获取字段信息.
if info, ok := reflect_type.FieldByName("name"); ok{
fmt.Printf("name is :%v, tag is: %v \n", info.Name, info.Tag.Get("json"))
}
}
}
>
Name(): girl kind(): struct
是结构体
index: 0, file name: name
index: 1, file name: age
index: 2, file name: high
name is :name, tag is: nikname
上面提到了 结构体的反射对象 StructField 里面有个 Struct Tag, 我们来看看这个 TAG 里面是神马东西把:
字段的额外信息, 这些信息都是静态的,无须实例化结构体,可以通过反射获取到
书写结构:
`key1:"value1" key2:"value2"`
结构体标签由一个或多个键值对组成;键与值使用冒号分隔,值用双引号括起来;键值对之间使用一个空格分隔, 这个格式很严格,有地方多一个空格都不会是期望的结果
取出 key 对应值:
reflect_type.FieldByName("xx").Tag.Get("json")
判断 key 是不是存在:
Lookup(key)
func (tag StructTag) Lookup(key string) (value string, ok bool)
reflect_type.FieldByName("xx").Tag.Lookup("json")
-
反射获取值 reflect.ValueOf
普通类型获取反射类型
value := reflect.ValueOf(rawValue)
返回 reflect.Value 类型
reflect.Value 是一些反射操作的重要类型,如反射调用函数
reflect.Value 对象所具有的方法
- 将值以 interface{} 类型返回
Interface() interface {}
- 将值以 int 类型返回(所有有符号整型均可以此方式返回)
Int() int64
- 值以 uint 类型返回(所有无符号整型均可以此方式返回)
Uint() uint64
- 值以双精度(float64)类型返回,所有浮点数(float32、float64)均可以此方式返回
Float() float64
- 将值以 bool 类型返回
Bool() bool
- 将值以字节数组 []bytes 类型返回
Bytes() []bytes
- 将值以字符串类型返回
String() string
结构体反射获取值
方法如下, 和获取信息的一样,子不过,获取的 是 Value 对象,不是 StructField 对象
- Field(i int) Value
- NumField() int
- FieldByName(name string) Value
- FieldByIndex(index []int) Value
- FieldByNameFunc(match func(string) bool) Value
关于 值类型的方法参考:
https://golang.google.cn/pkg/reflect/#Value
反射修改值
reflect.Value 修改值得方法(和 获取值是对应的):
Setlnt(x int64) SetUint(x uint64) SetFloat(x float64) SetBool(x bool)
SetBytes(x []byte SetString(x string)
可以被修改的条件:
传入地址
var a int = 1024
valueOfA := reflect.ValueOf(&a)
valueOfA = valueOfA.Elem()
valueOfA.SetInt(1)
结构体成员中,字段可导出
type dog struct {
LegCount int
}
valueOfDog := reflect.ValueOf(&dog{})
valueOfDog = valueOfDog.Elem()
vLegCount := valueOfDog.FieldByName("LegCount")
vLegCount.SetInt(4)