Go语言反射reflect深入理解(4)

反射值对象(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。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/98792baee2e8e1e9e62ecdf5d74bb646.html