来动态获取变量的类型和值,并进行操作。虽然 Go 是静态类型语言,但通过反射可以在运行时处理不确定类型的变量,这在开发一些通用工具、框架或需要动态行为的场景中非常有用。
一、了解 reflect 的基本结构
Go 的反射机制主要围绕两个核心概念:Type 和 Value。
reflect.Type
表示变量的类型信息
reflect.Value
表示变量的具体值
要使用反射,通常先调用
reflect.TypeOf()
或
reflect.ValueOf()
获取对应的信息:
var x float64 = 3.14
fmt.Println(reflect.TypeOf(x)) // 输出: float64
fmt.Println(reflect.ValueOf(x)) // 输出: 3.14
注意,
reflect.ValueOf()
返回的是一个副本,不能直接修改原始变量,除非传入指针。
二、通过反射设置变量的值
如果想通过反射修改变量的值,必须确保该变量是可寻址的(即传入指针)。
例如:
var a int = 10
v := reflect.ValueOf(&a).Elem() // 取指针对应的元素
v.SetInt(20)
fmt.Println(a) // 输出: 20
这里的关键点有几个:
使用
.Elem()
获取指针指向的实际值
调用
SetInt
、
SetString
等方法前,要确保类型匹配
如果变量不可修改(如常量、非指针等),会触发 panic
所以实际使用时建议加上判断:
v.CanSet()
判断是否可以设置值
v.Kind()
判断底层类型
三、反射结构体字段与方法
反射在结构体上的应用尤其广泛,比如 ORM 框架经常用它来自动映射数据库字段。
你可以通过
reflect.Type
遍历结构体字段,通过
reflect.Value
获取或设置字段值:
type User struct {
Name string
Age int
}
u := User{Name: "Tom", Age: 25}
t := reflect.TypeOf(u)
v := reflect.ValueOf(u)
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
value := v.Field(i)
fmt.Printf("字段名:%s, 类型:%s, 值:%v\n", field.Name, field.Type, value)
}