反射
反射是指程序运行时能够"观察"并"操作"自身结构的能力。
可以获取任意变量的 类型信息Type
获取或设置任意变量的值Value
调用方法、遍历结构体字段等
核心概念 reflect.Type 和 reflect.Value
reflect.Type
是一个接口,表示了任意类型的完整类型信息
基本信息
| 方法 | 返回值 | 说明 |
|---|---|---|
.Name() |
string |
类型在代码中的名字(如 Person),匿名类型返回空字符串 |
.PkgPath() |
string |
类型所在包的路径(仅对具名类型有效) |
.String() |
string |
类型的完整字符串表示(如 main.Person 或 []int) |
.Kind() |
reflect.Kind |
底层基本种类(如 Struct, Int, Slice 等) |
type MyInt int -> Name()="MyInt",Kind()=Int,PkgPath()="main"
| 方法 | 返回值 | 说明 |
|---|---|---|
.AssignableTo(u Type) |
bool |
当前类型是否可赋值给类型 u |
.ConvertibleTo(u Type) |
bool |
是否可通过类型转换转为 u |
.Implements(u Type) |
bool |
是否实现了接口 u(u 必须是接口类型) |
.Comparable() |
bool |
类型是否支持 == 和 != 比较 |
.Size() |
uintptr |
类型在内存中占用的字节数(类似 unsafe.Sizeof) |
.Align() |
int |
该类型在结构体中的对齐字节数 |
.FieldAlign() |
int |
作为结构体字段时的对齐字节数 |
Kind == Ptr()指针:.Elem()指针指向的类型
Array/Slice:.Elem()元素类型,.Len()数组长度
Map:.Key()键类型,.Elem值类型
Chan通道:.ChanDir()通道方向.Elem()通道元素类型
Func函数:.NumIn()/.NumOut()入参出参个数。.In(i)/.Out(i)第i个输入输出参数类型。.IsVariadic()是否变参。
Struct结构体:.NumField()字段数量,.Field(i)第i个字段,.FieldByName(name),.FieldByIndex(index)按嵌套索引访问字段。
reflect.Value
是一个结构体,封装了任意变量的值。
通过reflecy.ValueOf(x)获取,通过.Interface()方法还原。
| 方法 | 说明 |
|---|---|
.Kind() |
返回底层种类(如 Int, String, Struct) |
.Type() |
返回对应的 reflect.Type |
.IsValid() |
判断值是否有效(零值 Value{} 无效) |
.IsZero() |
判断是否为类型的零值(Go 1.13+) |
▶ 结构体(Struct)
-
.NumField()/.Field(i)→ 字段数量和字段值(Value) -
.FieldByName(name)→ 按名称获取字段 -
.FieldByIndex([]int)→ 支持嵌套字段访问
▶ 切片/数组(Slice/Array)
-
.Len()/.Cap()→ 长度和容量 -
.Index(i)→ 获取第 i 个元素(返回Value) -
.SetIndex(i, value)→ 设置元素(需可寻址)
▶ 映射(Map)
-
.MapKeys()→ 所有 key 的[]Value -
.MapIndex(key)→ 获取值 -
.SetMapIndex(key, val)→ 设置或删除(val 为零值则删除)
▶ 指针(Ptr)
.Elem()→ 解引用,获取指向的值
▶ 函数/方法(Func)
-
.Call(args []Value)→ 调用函数 -
.CallSlice(args []Value)→ 调用带...参数的函数
例子
获取值
Go
v := reflect.ValueOf(100)
fmt.Println(v.Int()) // 输出: 100
设置值(必须为指针,Value可寻址)
Go
x := 10
v := reflect.ValueOf(&x).Elem()
if v.CanSet() {
v.SetInt(200)
}
fmt.Println(x) // 输出: 200
结构体字段和方法操作
Go
type User struct {
Name string
Age int
}
u := User{"Alice", 30}
v := reflect.ValueOf(u)
t := reflect.TypeOf(u)
for i := 0; i < v.NumField(); i++ {
fmt.Printf("Field %s = %v\n", t.Field(i).Name, v.Field(i))
}
动态设置结构体字段
Go
u := User{"Bob", 25}
v := reflect.ValueOf(&u).Elem()
v.FieldByName("Name").SetString("Charlie")
fmt.Println(u.Name) // 输出: Charlie
调用结构体方法
Go
type Person struct{}
func (p Person) Say(name string) {
fmt.Println("Hello,", name)
}
p := Person{}
v := reflect.ValueOf(p)
m := v.MethodByName("Say")
args := []reflect.Value{reflect.ValueOf("Go")}
m.Call(args) // 输出: Hello, Go