Go 语言标准库中reflect模块详细功能介绍与示例

Go语言的 reflect 模块提供了强大的反射功能,允许程序在运行时检查类型信息、操作变量值及调用方法。以下是对 reflect 模块核心方法的详细说明及示例:


1. 获取类型信息

reflect.TypeOf

获取变量的类型信息,返回 reflect.Type 对象。

go 复制代码
package main

import (
    "fmt"
    "reflect"
)

func main() {
    var x int = 42
    t := reflect.TypeOf(x)
    fmt.Println(t) // 输出: int
}

2. 获取值信息

reflect.ValueOf

获取变量的值信息,返回 reflect.Value 对象。

go 复制代码
func main() {
    x := 42
    v := reflect.ValueOf(x)
    fmt.Println(v) // 输出: 42
}

3. 从 Value 中获取实际值

Value.Interface()

Value 转换为 interface{},需类型断言。

go 复制代码
func main() {
    x := 42
    v := reflect.ValueOf(x)
    val := v.Interface().(int)
    fmt.Println(val) // 输出: 42
}
Value.Int(), Value.String(), 等

直接获取基础类型的值(需类型匹配)。

go 复制代码
func main() {
    v := reflect.ValueOf(42)
    fmt.Println(v.Int()) // 输出: 42

    s := reflect.ValueOf("hello")
    fmt.Println(s.String()) // 输出: hello
}

4. 检查类型种类

Type.Kind()Value.Kind()

返回类型的底层种类(如 int, struct, slice)。

go 复制代码
func main() {
    x := 42
    t := reflect.TypeOf(x)
    fmt.Println(t.Kind()) // 输出: int

    v := reflect.ValueOf(x)
    fmt.Println(v.Kind()) // 输出: int
}

5. 操作结构体字段

Type.NumField()Value.Field(i)

遍历结构体的字段。

go 复制代码
type Person struct {
    Name string
    Age  int
}

func main() {
    p := Person{"Alice", 30}
    t := reflect.TypeOf(p)
    v := reflect.ValueOf(p)

    for i := 0; i < t.NumField(); i++ {
        field := t.Field(i)
        value := v.Field(i)
        fmt.Printf("%s: %v\n", field.Name, value)
    }
    // 输出:
    // Name: Alice
    // Age: 30
}

6. 调用方法

Value.MethodByNameValue.Call

动态调用结构体的方法。

go 复制代码
type Math struct{}

func (m Math) Add(a, b int) int {
    return a + b
}

func main() {
    m := Math{}
    v := reflect.ValueOf(m)
    method := v.MethodByName("Add")
    args := []reflect.Value{reflect.ValueOf(3), reflect.ValueOf(5)}
    result := method.Call(args)
    fmt.Println(result[0].Int()) // 输出: 8
}

7. 修改值

Value.Elem()Value.Set

修改指针指向的值(需确保可设置)。

go 复制代码
func main() {
    x := 42
    v := reflect.ValueOf(&x).Elem()
    v.SetInt(43)
    fmt.Println(x) // 输出: 43
}

8. 创建实例

reflect.New

根据类型创建新实例的指针。

go 复制代码
func main() {
    t := reflect.TypeOf(0) // int 类型
    v := reflect.New(t)    // 创建 *int
    v.Elem().SetInt(100)
    fmt.Println(v.Elem().Int()) // 输出: 100
}

9. 处理切片和映射

reflect.MakeSlicereflect.MakeMap

动态创建切片或映射。

go 复制代码
func main() {
    // 创建切片
    sliceType := reflect.TypeOf([]int(nil))
    slice := reflect.MakeSlice(sliceType, 0, 5)
    slice = reflect.Append(slice, reflect.ValueOf(1), reflect.ValueOf(2))
    fmt.Println(slice) // 输出: [1 2]

    // 创建映射
    mapType := reflect.TypeOf(map[string]int{})
    m := reflect.MakeMap(mapType)
    key := reflect.ValueOf("a")
    value := reflect.ValueOf(100)
    m.SetMapIndex(key, value)
    fmt.Println(m) // 输出: map[a:100]
}

10. 处理函数

reflect.FuncOfreflect.MakeFunc

动态创建函数。

go 复制代码
func main() {
    // 定义函数类型: func(int, int) int
    funcType := reflect.FuncOf(
        []reflect.Type{reflect.TypeOf(0), reflect.TypeOf(0)},
        []reflect.Type{reflect.TypeOf(0)},
        false,
    )

    // 实现函数逻辑
    adder := reflect.MakeFunc(funcType, func(args []reflect.Value) []reflect.Value {
        a := args[0].Int()
        b := args[1].Int()
        return []reflect.Value{reflect.ValueOf(a + b)}
    })

    // 调用动态函数
    result := adder.Call([]reflect.Value{reflect.ValueOf(3), reflect.ValueOf(5)})
    fmt.Println(result[0].Int()) // 输出: 8
}

11. 检查是否可设置

Value.CanSet()

验证 Value 是否可修改。

go 复制代码
func main() {
    x := 42
    v := reflect.ValueOf(x)
    fmt.Println(v.CanSet()) // 输出: false(非指针传递)

    v = reflect.ValueOf(&x).Elem()
    fmt.Println(v.CanSet()) // 输出: true
}

总结

  • 核心方法
    • 类型/值获取:TypeOf, ValueOf
    • 结构体操作:NumField, Field, MethodByName
    • 值修改:Elem, Set, CanSet
    • 动态创建:New, MakeSlice, MakeMap, MakeFunc
  • 适用场景
    • 序列化/反序列化(如JSON、XML解析)
    • ORM框架中的动态模型处理
    • 依赖注入或动态函数调用
  • 注意事项
    • 反射代码性能较低,应避免频繁使用。
    • 操作未导出字段需谨慎,可能破坏封装性。
    • 类型不匹配会导致运行时panic,需提前检查 Kind
相关推荐
xyliiiiiL30 分钟前
从责任链模式聊到aware接口
java·开发语言
Elec_z2 小时前
网络深处的守门人
开发语言·网络
闪电麦坤953 小时前
C#:Time.deltaTime
开发语言·c#
Alfadi联盟 萧瑶5 小时前
Python-Django入手
开发语言·python·django
codingandsleeping5 小时前
浏览器的缓存机制
前端·后端
-代号95276 小时前
【JavaScript】十二、定时器
开发语言·javascript·ecmascript
勘察加熊人6 小时前
c++实现录音系统
开发语言·c++
self-discipline6346 小时前
【Java】Java核心知识点与相应面试技巧(七)——类与对象(二)
java·开发语言·面试
wei3872452326 小时前
java笔记02
java·开发语言·笔记
追逐时光者6 小时前
面试官问:你知道 C# 单例模式有哪几种常用的实现方式?
后端·.net