反射值对象(reflect.Value)提供对结构体访问的方法,通过这些方法可以完成对结构体任意值的访问,如下表所示。
方 法备 注Field(i int) Value 根据索引,返回索引对应的结构体成员字段的反射值对象。当值不是结构体或索引超界时发生宕机
NumField() int 返回结构体成员字段数量。当值不是结构体或索引超界时发生宕机
FieldByName(name string) Value 根据给定字符串返回字符串对应的结构体字段。没有找到时返回零值,当值不是结构体或索引超界时发生宕机
FieldByIndex(index []int) Value 多层成员访问时,根据 []int 提供的每个结构体的字段索引,返回字段的值。 没有找到时返回零值,当值不是结构体或索引超界时发生宕机
FieldByNameFunc(match func(string) bool) Value 根据匹配函数匹配需要的字段。找到时返回零值,当值不是结构体或索引超界时发生宕机
下面代码构造一个结构体包含不同类型的成员。通过 reflect.Value 提供的成员访问函数,可以获得结构体值的各种数据。
反射访问结构体成员的值:
package main import ( "fmt" "reflect" ) //定义结构体 type Student struct { Name string Age int //嵌入字段 float32 bool next *Student } func main() { //值包装结构体 rValue := reflect.ValueOf(Student{ next: &Student{}, }) //获取字段数量 fmt.Println("NumField:", rValue.NumField()) //获取索引为2的字段(float32字段) //注:经过测试发现Field(i)的参数索引是从0开始的, //并且是按照定义的结构体的顺序来的,而不是按照字段名字的ASCii码值来的 floatField := rValue.Field(2) //输出字段类型 fmt.Println("Field:", floatField.Type()) //根据名字查找字段 fmt.Println("FieldByName(\"Age\").Type:", rValue.FieldByName("Age").Type()) //根据索引查找值中next字段的int字段的值 fmt.Println("FieldByIndex([]int{4, 0}).Type()", rValue.FieldByIndex([]int{4, 0}).Type()) }输出结果为:
NumField: 5 Field: float32 FieldByName("Age").Type: int FieldByIndex([]int{4, 0}).Type() string代码说明如下:
第 9 行,定义结构体,结构体的每个字段的类型都不一样。
第 24 行,实例化结构体并包装为 reflect.Value 类型,成员中包含一个 *Student 的实例。
第 29 行,获取结构体的字段数量。
第 34 和 37 行,获取索引为2的字段值(float32 字段),并且打印类型。
第 39 行,根据Age字符串,查找到 Age 字段的类型。
第 41 行,[]int{4,0} 中的 4 表示,在 Student 结构中索引值为 4 的成员,也就是 next。next 的类型为 Student,也是一个结构体,因此使用 []int{4,0} 中的 0 继续在 next 值的基础上索引,结构为 Student 中索引值为 0 的 Name 字段,类型为 string。
判断反射值得空和有效性IsNil()和IsValid() -- 判断反射值的空和有效性
反射值对象(reflect.Value)提供一系列方法进行零值和空判定,如下表所示。
反射值对象的零值和有效性判断方法 方 法说 明IsNil() bool 返回值是否为 nil。如果值类型不是通道(channel)、函数、接口、map、指针或 切片时发生 panic,类似于语言层的v== nil操作
IsValid() bool 判断值是否有效。 当值本身非法时,返回 false,例如 reflect Value不包含任何值,值为 nil 等。
下面的例子将会对各种方式的空指针进行 IsNil() 和 IsValid() 的返回值判定检测。同时对结构体成员及方法查找 map 键值对的返回值进行 IsValid() 判定,参考下面的代码。
反射值对象的零值和有效性判断:
package main import ( "fmt" "reflect" ) func main() { //*int的空指针 var a *int fmt.Println("var a *int:", reflect.ValueOf(a).IsNil()) //nil值 fmt.Println("nil:", reflect.ValueOf(nil).IsValid()) //*int类型的空指针 fmt.Println("(*int)(nil):", reflect.ValueOf((*int)(nil)).Elem().IsValid()) //实例化一个结构体 s := struct {}{} //尝试从结构体中查找一个不存在的字段 fmt.Println("不存在的结构体成员:", reflect.ValueOf(s).FieldByName("").IsValid()) //尝试从结构体中查找一个不存在的方法 fmt.Println("不存在的方法:", reflect.ValueOf(s).MethodByName("").IsValid()) //实例化一个map m := map[int]int{} //尝试从map中查找一个不存在的键 fmt.Println("不存在的键:", reflect.ValueOf(m).MapIndex(reflect.ValueOf(3)).IsValid()) }输出结果:
var a *int: true nil: false (*int)(nil): false 不存在的结构体成员: false 不存在的方法: false 不存在的键: false代码说明如下:
第 11 行,声明一个 *int 类型的指针,初始值为 nil。
第 12 行,将变量 a 包装为 reflect.Value 并且判断是否为空,此时变量 a 为空指针,因此返回 true。
第 15 行,对 nil 进行 IsValid() 判定(有效性判定),返回 false。