Skip to content
On this page

反射

反射允许程序在运行时检查类型信息和操作对象。本章将详细介绍 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))
}

最佳实践

  1. 避免过度使用:反射比直接访问慢
  2. 缓存反射结果:避免重复反射
  3. 错误处理:检查类型和可设置性
  4. 文档说明:明确使用反射的地方
  5. 性能敏感代码:避免使用反射

总结

  • 反射允许运行时类型检查
  • 使用 reflect.Type 和 reflect.Value
  • 可以修改值和调用方法
  • 支持结构体、Map、Slice 等
  • 性能比直接访问慢
  • 谨慎使用,文档说明

下一章:泛型

基于 MIT 许可发布