摘要:理解Go语言的反射机制,反射是指在程序运行期对程序本身进行访问和修改的能力。
反射基础信息
func reflectDemo() {
str := "reflect"
fmt.Println(reflect.ValueOf(str))
fmt.Println(reflect.TypeOf(str))
}
// 结果
// reflect
// string
reflect.ValueOf()获取数据运行时的值。 reflect.TypeOf()获取数据类型信息。
// Type values are comparable, such as with the == operator,
// so they can be used as map keys.
// Two Type values are equal if they represent identical types.
type Type interface {
// To compare two Values, compare the results of the Interface method.
// Using == on two Values does not compare the underlying values
// they represent.
type Value struct {
从源码中可以看出,Type是个interface,而Value是个struct。
reflect包中除了有TypeOf还有kind,type是具体的类型信息,kind是类型的种类,基本数据类型type和kind是一样的。
fmt.Println(reflect.TypeOf(dog{}))
typeOf := reflect.TypeOf(dog{})
fmt.Println(typeOf.Kind())
// reflect_demo.dog
// struct
反射指针元素
func reflectDemo1() {
list := &ListNode{}
fmt.Println("reflect.TypeOf ", reflect.TypeOf(list))
fmt.Println("reflect value ", reflect.ValueOf(list))
fmt.Println("reflect kind ", reflect.TypeOf(list).Kind())
}
type ListNode struct {
val int
next *ListNode
}
// 结果:
// reflect.TypeOf *reflect_demo.ListNode
// reflect value &{0 <nil>}
// reflect kind ptr
ptr 是指针类型。 示例中的指针是个结构体指针,通过反射机制可以获取到结构体中的字段信息。
func reflectDemo2() {
list := ListNode{val: 12, next: nil}
typeOf := reflect.TypeOf(list)
for i := 0; i < typeOf.NumField(); i++ {
fieldType := typeOf.Field(i)
fmt.Println("fileName: ", fieldType.Name, " fileType: ", fieldType.Type, " fieldTag: ", fieldType.Tag)
}
}
type ListNode struct {
Name string `json:"Name"`
val int
next *ListNode
}
// 输出
// fileName: Name fileType: string fieldTag: json:"name"
// fileName: val fileType: int fieldTag:
// fileName: next fileType: *reflect_demo.ListNode fieldTag:
typeOf.Field(i) 可以获取结构体中的字段信息,注意这里的list不能是指针类型,why? 因为这是个指针,不是结构体,可以通过Elem()方法获取指向的元素。
list := &ListNode{val: 12, next: nil}
typeOf := reflect.TypeOf(list)
if typeOf.Kind() == reflect.Ptr {
for i := 0; i < typeOf.Elem().NumField(); i++ {
fieldType := typeOf.Elem().Field(i)
fmt.Println("fileName: ", fieldType.Name, " fileType: ", fieldType.Type, " fieldTag: ", fieldType.Tag)
}
}
还有一种方式,通过value也可以获取元素的kind等信息。
func reflectDemo3() {
list := &ListNode{val: 12, next: nil}
indirect := reflect.Indirect(reflect.ValueOf(list))
if indirect.Kind() == reflect.Ptr {
fmt.Println("Ptr")
}
if indirect.Kind() == reflect.Struct {
fmt.Println("struct")
}
}
// 输出
// struct