Go reflect:运行时反射与元编程
探索reflect包,学习如何在运行时检查类型、读写值、调用方法以及处理结构体标签。 · 难度:入门 · +15XP
反射:运行时自省
反射允许程序在运行时检查自身类型和值,甚至修改值。Go的reflect包提供了强大的元编程能力,但应谨慎使用(性能较低且破坏类型安全)。
1. reflect.Type 和 reflect.Value
通过reflect.TypeOf()和reflect.ValueOf()获取类型和值信息:
var x float64 = 3.14
t := reflect.TypeOf(x) // float64
v := reflect.ValueOf(x) // 3.14
fmt.Println(t.Name()) // float64
fmt.Println(v.Kind()) // Float64
fmt.Println(v.Float()) // 3.14
2. 修改值(需要可寻址)
要修改值,必须传递指针并使用Elem():
var x float64 = 3.14
v := reflect.ValueOf(&x).Elem() // 获取指针指向的值
if v.CanSet() {
v.SetFloat(2.71)
}
fmt.Println(x) // 2.713. 结构体字段遍历
type User struct {
Name string json:"name"
Age int json:"age"
}
u := User{"Alice", 30}
t := reflect.TypeOf(u)
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
value := reflect.ValueOf(u).Field(i)
fmt.Printf("%s (%s): %v [json tag: %s]
",
field.Name, field.Type, value.Interface(),
field.Tag.Get("json"))
}
// 输出:
// Name (string): Alice [json tag: name]
// Age (int): 30 [json tag: age]
4. 动态调用方法
type Calculator struct{}
func (c Calculator) Add(a, b int) int { return a + b }
v := reflect.ValueOf(Calculator{})
method := v.MethodByName("Add")
args := []reflect.Value{
reflect.ValueOf(10),
reflect.ValueOf(20),
}
result := method.Call(args)
fmt.Println(result[0].Int()) // 30
5. 常见用途
| 用途 | 说明 |
|---|---|
| JSON/XML序列化 | 读取结构体标签自动编码 |
| ORM框架 | 根据结构体生成SQL语句 |
| 测试工具 | 自动填充测试数据 |
6. 练习提示
下方代码中,实现一个PrintStruct函数,使用反射打印任意结构体的字段名、类型和值(格式:字段名 (类型) = 值)。提示:使用reflect.TypeOf和reflect.ValueOf。