Go中 反射

152 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第22天,点击查看活动详情

开发时经常会遇到字符串与结构体之间的转换。使用比较多的用法就是通过反射的方法将一个 JSON 字符串转换为 struct 结构体。

反射

Go 是静态编译类语言,对于变量类型,函数方法传递的参数的类型都是已知的。但当 你定义函数的参数是 interface{}类型,那任何类型都可以传递给它,那在函数体内使用时就需要使用反射

在 Go 反射中,标准库为我们提供了两种类型 reflect.Value 和 reflect.Type 来分别表示变量的值和类型,并且提供了两个函数 reflect.ValueOf 和 reflect.TypeOf 分别获取任意对象的 reflect.Value 变量的值 和 reflect.Type 变量的类型。

func main() {
    val := "hello"
    iv := reflect.ValueOf(val)
    it := reflect.TypeOf(val)

    fmt.Println(iv, it)
}

reflect.Value

reflect.ValueOf 的返回值是 Value 结构体类型:

 type Value struct {
   typ *rtype
   ptr unsafe.Pointer
   flag
 }

Value 结构体的字段都是私有的。所以只能使用 reflect.Value 的方法。使用reflect.ValueOf 函数把任意类型的对象转为一个 reflect.Value。而如果要逆向转回来使用 interface 方法

val := "hello"
iv := reflect.ValueOf(val)
i1:=iv.Interface().(string) // 反向转

反射获取了对应的值,也支持通过反射在运行时修改值。要修改值需要符合反射值的规则:

  • 可被寻值,既通过 reflect.ValueOf(&param) ,参数是指针
  • 修改类型为结构体的值,则结构体的字段都必须是公有的
  • 使用 Elem 方法获得指针指向的值,然后使用 Set 系列方法修改值
func main() {
    type person struct {
        Name string
        Age  int
    }
    val := person{"nanxi", 13}

    iv := reflect.ValueOf(&val)
    iv.Elem().Field(0).SetString("jerry") // 修改了值

    fmt.Println(iv)

}

reflect.Type

要反射获取一个变量的 reflect.Type,可以通过函数 reflect.TypeOf。reflect.TypeOf 的返回值是 Type 接口类型。这个和获取值不一样返回的是结构体。作用:

  • 通过 TypeOf 可以获取结构体的字段的类型和方法
  • 用来判断是否实现了某接口,当然该方式尽量少使用,应该使用类型断言的方式去判断是否实现某接口。