Hi 亲爱的朋友们,我是 k 哥。今天,咱们来一同探讨下 Golang 反射。
Go 出于通用性的考量,提供了反射这一功能。借助反射功能,我们可以实现通用性更强的函数,传入任意的参数,在函数内通过反射动态调用参数对象的方法并访问它的属性。举例来说,下面的bridge接口为了支持灵活调用任意函数,在运行时根据传入参数funcPtr,通过反射动态调用funcPtr指向的具体函数。
func bridge(funcPtr interface{}, args ...interface{})
再如,ORM框架函数为了支持处理任意参数对象,在运行时根据传入的参数,通过反射动态对参数对象赋值。
type User struct {
Name string
Age int32
}
user := User{}
db.FindOne(&user)
本文将深入探讨Golang反射包reflect的功能和原理。同时,我们学习某种东西,一方面是为了实践运用,另一方面则是出于功利性面试的目的。所以,本文还会为大家介绍反射的典型应用以及高频面试题。
1 关键功能
reflect包提供的功能比较多,但核心功能是把interface变量转化为反射类型对象reflect.Type和reflect.Value,并通过反射类型对象提供的功能,访问真实对象的方法和属性。本文只介绍3个核心功能,其它方法可看官方文档。
1.对象类型转换。通过TypeOf和ValueOf方法,可以将interface变量转化为反射类型对象Type和Value。通过Interface方法,可以将Value转换回interface变量。
type any = interface{}
// 获取反射对象reflect.Type
// TypeOf returns the reflection Type that represents the dynamic type of i.
// If i is a nil interface value, TypeOf returns nil.
func TypeOf(i any) Type
// 获取反射对象reflect.Value
// ValueOf returns a new Value initialized to the concrete value stored in the interface i.
// ValueOf(nil) returns the zero Value.
func ValueOf(i any) Value
// 反射对象转换回interface
func (v Value) Interface() (i any)
示例如下:
package main
import (
"fmt"
"reflect"
)
func main() {
age := 18
fmt.Println("type: ", reflect.TypeOf(age)) // 输出type: int
value := reflect.ValueOf(age)
fmt.Println("value: ", value) // 输出value: 18
fmt.Println(value.Interface().(int)) // 输出18
}
2.变量值设置。通过reflect.Value的SetXX相关方法,可以设置真实变量的值。reflect.Value是通过reflect.ValueOf(x)获得的,只有当x是指针的时候,才可以通过reflec.Value修改实际变量x的值。
// Set assigns x to the value v. It panics if Value.CanSet returns false.
// As in Go, x's value must be assignable to v's type and must not be derived from an unexported field.
func (v Value) Set(x Value)
func (v Value) SetInt(x int64)
...
// Elem returns the value that the interface v contains or that the pointer v points to. It panics if v's Kind is