Go语言反射

2021/06/17

Tags: Go

摘要:理解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