Go语言反射 | 青训营笔记

57 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 15 天,记录对 go 语言反射的学习。

什么是反射

反射指程序可以访问、检测和修改它本身状态或行为的一种能力。

Go 语言的反射可以让我们在运行时更新和检查变量的值、调用变量的方法和变量支持的内在操作(但是在编译时并不知道这些变量的具体类型),也可以让我们将类型本身作为第一类的值类型处理。

Go 语言的反射功能由 reflect 包提供,它定义了两个重要的类型 Type 和 Value,并且提供了 reflect.TypeOf() 和 reflect.ValueOf() 两个函数来获取任意对象的 Value 和 Type。

获取类型

可以使用 refect.TypeOf() 函数来获取任意对象的类型,该类型对象的类型为 reflect.Type。

使用 reflect.Type 中的 Name() 方法可以获得类型的名称(该类型必须显示定义,否则会得到空字符串),使用 reflect.Type 中的 Kind() 方法可以获得一个类型为 reflect.Kind 的枚举值(结构体总是返回 reflect.Struct,指针总是返回 reflect.Pointer)。

 package main
 ​
 import (
     "fmt"
     "reflect"
 )
 ​
 type A struct {}
 ​
 func main() {
     i := 1
     typeOf := reflect.TypeOf(i)
     fmt.Println(typeOf, typeOf.Name(), typeOf.Kind())
 ​
     a := A{}
     typeOf = reflect.TypeOf(a)
     fmt.Println(typeOf, typeOf.Name(), typeOf.Kind())
 ​
     typeOf = reflect.TypeOf(&a)
     fmt.Println(typeOf, typeOf.Name(), typeOf.Kind())
 }
 // 输出
 int int int
 main.A A struct
 *main.A  ptr
获取值

可以使用 refect.ValueOf() 函数来获取任意对象的值,该值对象的类型为 reflect.Value。

 package main
 ​
 import (
     "fmt"
     "reflect"
 )
 ​
 func main() {
     i := 100
     valueOf := reflect.ValueOf(i)
     var c int = int(valueOf.Int())
     fmt.Println(c)
 }
 // 输出
 100
获取结构体字段信息

使用 reflect.Type 的 Field() 或者 FieldByName() 方法可以获取结构体字段的信息,类型为 reflect.StructField。

 type StructField struct {
     Name string          // 字段名
     PkgPath string       // 字段路径
     Type      Type       // 字段反射类型对象
     Tag       StructTag  // 字段的结构体标签
     Offset    uintptr    // 字段在结构体中的相对偏移
     Index     []int      // Type.FieldByIndex中的返回的索引值
     Anonymous bool       // 是否为匿名字段
 }

使用reflect.Value 的 Field() 或者 FieldByName() 方法可以获取结构体字段的值。

获取结构体标签

结构体标签规范:由一个或多个键值对组成,键与值使用冒号分隔,值要加上双引号,键值对之间使用空格分隔。

 `key1:"value2" key2:"value2"`

可以使用 reflect.Tag.Get() 方法来获取 tag 对应 key 的值。

 package main
 ​
 import (
     "fmt"
     "reflect"
 )
 ​
 type User struct {
     Id string `json:"id"`
     Name string `json:"name"`
 }
 ​
 func main() {
     typeOf := reflect.TypeOf(User{})
     name, _ := typeOf.FieldByName("Name")
     fmt.Println(name.Tag.Get("json"))
 }
 // 输出
 name
参考

pkg.go.dev/reflect

c.biancheng.net/golang/refl…