反射
反射允许程序在运行时检查类型信息和操作对象。本章将详细介绍 Go 的反射机制。
反射基础
Type 和 Value
go
package main
import (
"fmt"
"reflect"
)
func main() {
var x int = 42
// 获取类型
t := reflect.TypeOf(x)
fmt.Println("类型:", t)
fmt.Println("类型名称:", t.Name())
fmt.Println("类型种类:", t.Kind())
// 获取值
v := reflect.ValueOf(x)
fmt.Println("值:", v)
fmt.Println("值的类型:", v.Type())
fmt.Println("值的种类:", v.Kind())
fmt.Println("整数值:", v.Int())
}
Kind 类型
go
func printKind(v interface{}) {
t := reflect.TypeOf(v)
fmt.Printf("%v 的种类是 %s\n", v, t.Kind())
}
func main() {
printKind(42) // int
printKind(3.14) // float64
printKind("hello") // string
printKind(true) // bool
printKind([3]int{1,2,3}) // array
printKind([]int{1,2,3}) // slice
printKind(map[int]int{}) // map
printKind(make(chan int)) // chan
}
反射操作
修改值
go
func main() {
var x int = 42
v := reflect.ValueOf(&x)
v = v.Elem()
v.SetInt(100)
fmt.Println(x) // 100
}
调用方法
go
type Person struct {
Name string
}
func (p Person) SayHello() {
fmt.Printf("Hello, %s!\n", p.Name)
}
func (p *Person) SetName(name string) {
p.Name = name
}
func main() {
p := Person{Name: "张三"}
v := reflect.ValueOf(p)
// 调用值方法
method := v.MethodByName("SayHello")
method.Call(nil)
// 调用指针方法
pv := reflect.ValueOf(&p)
setMethod := pv.MethodByName("SetName")
args := []reflect.Value{reflect.ValueOf("李四")}
setMethod.Call(args)
fmt.Println(p.Name)
}
获取结构体字段
go
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
func main() {
u := User{ID: 1, Name: "张三", Email: "zhangsan@example.com"}
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, 标签: %s\n",
field.Name, field.Type, value, field.Tag)
}
}
修改结构体字段
go
type User struct {
Name string
Age int
}
func main() {
u := User{Name: "张三", Age: 25}
v := reflect.ValueOf(&u).Elem()
nameField := v.FieldByName("Name")
nameField.SetString("李四")
ageField := v.FieldByName("Age")
ageField.SetInt(30)
fmt.Printf("%+v\n", u)
}
反射与接口
类型断言
go
func process(v interface{}) {
t := reflect.TypeOf(v)
switch t.Kind() {
case reflect.Int:
fmt.Println("整数:", v)
case reflect.String:
fmt.Println("字符串:", v)
case reflect.Slice:
fmt.Println("切片:", v)
default:
fmt.Println("其他类型:", v)
}
}
func main() {
process(42)
process("hello")
process([]int{1, 2, 3})
}
动态创建对象
go
func createInstance(t reflect.Type) interface{} {
return reflect.New(t).Elem().Interface()
}
func main() {
var user struct {
Name string
Age int
}
t := reflect.TypeOf(user)
instance := createInstance(t)
fmt.Printf("类型: %T, 值: %v\n", instance, instance)
}
反射与函数
调用函数
go
func add(a, b int) int {
return a + b
}
func main() {
fn := reflect.ValueOf(add)
args := []reflect.Value{
reflect.ValueOf(10),
reflect.ValueOf(20),
}
results := fn.Call(args)
fmt.Println("结果:", results[0].Int())
}
可变参数函数
go
func sum(nums ...int) int {
total := 0
for _, num := range nums {
total += num
}
return total
}
func main() {
fn := reflect.ValueOf(sum)
args := []reflect.Value{
reflect.ValueOf(1),
reflect.ValueOf(2),
reflect.ValueOf(3),
}
results := fn.Call(args)
fmt.Println("结果:", results[0].Int())
}
反射与 Map
遍历 Map
go
func printMap(m interface{}) {
v := reflect.ValueOf(m)
if v.Kind() != reflect.Map {
fmt.Println("不是 map")
return
}
for _, key := range v.MapKeys() {
value := v.MapIndex(key)
fmt.Printf("%v: %v\n", key.Interface(), value.Interface())
}
}
func main() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
}
printMap(m)
}
修改 Map
go
func main() {
m := map[string]int{"a": 1}
v := reflect.ValueOf(m)
v.SetMapIndex(reflect.ValueOf("b"), reflect.ValueOf(2))
v.SetMapIndex(reflect.ValueOf("a"), reflect.ValueOf(10))
fmt.Println(m)
}
反射与 Slice
遍历 Slice
go
func printSlice(s interface{}) {
v := reflect.ValueOf(s)
if v.Kind() != reflect.Slice {
fmt.Println("不是 slice")
return
}
for i := 0; i < v.Len(); i++ {
fmt.Printf("[%d] %v\n", i, v.Index(i).Interface())
}
}
func main() {
s := []int{1, 2, 3, 4, 5}
printSlice(s)
}
修改 Slice
go
func main() {
s := []int{1, 2, 3}
v := reflect.ValueOf(&s).Elem()
// 修改元素
v.Index(0).SetInt(10)
// 添加元素
v.SetLen(4)
v.Index(3).SetInt(4)
fmt.Println(s)
}
反射的应用
JSON 序列化
go
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
func toJSON(v interface{}) (string, error) {
t := reflect.TypeOf(v)
vValue := reflect.ValueOf(v)
if t.Kind() == reflect.Ptr {
t = t.Elem()
vValue = vValue.Elem()
}
if t.Kind() != reflect.Struct {
return "", fmt.Errorf("需要结构体类型")
}
result := "{"
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
value := vValue.Field(i)
jsonTag := field.Tag.Get("json")
if jsonTag == "" {
continue
}
if i > 0 {
result += ","
}
result += fmt.Sprintf(`"%s":%v`, jsonTag, value.Interface())
}
result += "}"
return result, nil
}
func main() {
user := User{ID: 1, Name: "张三", Email: "zhangsan@example.com"}
json, err := toJSON(user)
if err != nil {
fmt.Println("错误:", err)
return
}
fmt.Println(json)
}
依赖注入
go
type Container struct {
services map[reflect.Type]interface{}
}
func NewContainer() *Container {
return &Container{
services: make(map[reflect.Type]interface{}),
}
}
func (c *Container) Register(service interface{}) {
t := reflect.TypeOf(service)
c.services[t] = service
}
func (c *Container) Get(service interface{}) error {
t := reflect.TypeOf(service)
if t.Kind() != reflect.Ptr {
return fmt.Errorf("需要指针类型")
}
t = t.Elem()
service, ok := c.services[t]
if !ok {
return fmt.Errorf("服务未注册: %v", t)
}
v := reflect.ValueOf(service)
reflect.ValueOf(service).Elem().Set(v)
return nil
}
type Database struct {
Name string
}
type Cache struct {
Name string
}
func main() {
container := NewContainer()
db := &Database{Name: "MySQL"}
cache := &Cache{Name: "Redis"}
container.Register(db)
container.Register(cache)
var db2 *Database
var cache2 *Cache
container.Get(&db2)
container.Get(&cache2)
fmt.Printf("DB: %v\n", db2)
fmt.Printf("Cache: %v\n", cache2)
}
反射的性能
性能比较
go
func directAccess(u User) string {
return u.Name
}
func reflectAccess(u User) string {
v := reflect.ValueOf(u)
return v.FieldByName("Name").String()
}
func main() {
u := User{Name: "张三"}
// 直接访问
start := time.Now()
for i := 0; i < 1000000; i++ {
directAccess(u)
}
fmt.Println("直接访问:", time.Since(start))
// 反射访问
start = time.Now()
for i := 0; i < 1000000; i++ {
reflectAccess(u)
}
fmt.Println("反射访问:", time.Since(start))
}
最佳实践
- 避免过度使用:反射比直接访问慢
- 缓存反射结果:避免重复反射
- 错误处理:检查类型和可设置性
- 文档说明:明确使用反射的地方
- 性能敏感代码:避免使用反射
总结
- 反射允许运行时类型检查
- 使用 reflect.Type 和 reflect.Value
- 可以修改值和调用方法
- 支持结构体、Map、Slice 等
- 性能比直接访问慢
- 谨慎使用,文档说明
下一章:泛型