Golang 反射系统
概要
Golang 的类型系统包括 泛型 (Generics)、类型转换 (Type Conversion) 和 反射 (Reflection)。其核心关系如下:
- Interface:是方法的集合,用于实现多态。
- Type:表示变量的数据类型,包括基本类型、结构体、接口等。
- Value:表示变量的具体值。
- Reflect:通过
reflect
包动态操作 Type 和 Value,包括reflect.TypeOf()
和reflect.ValueOf()
。 - 泛型:通过类型参数(如
T any
)实现类型安全且可复用的函数与结构体。
关键概念
1. Interface、Type、Value 的关系
interface{}
:空接口可以存储任何类型。- interface有两个值,一个是value的type,一个是实际的value。
reflect.TypeOf(v)
:返回变量v
的 类型。reflect.ValueOf(v)
:返回变量v
的 值,并提供修改和调用的方法。
2. 泛型系统
- 泛型使用
type T any
定义类型参数。 any
相当于interface{}
,但可用于泛型。
分析一个struct的type和value
struct/interface
- Type
reflect.TypeOf(v)
Name()
类型名Kind()
底层基本类型(如struct、interface、)NumField()
字段数量Field(i int)
返回第 i 个字段的StructField
StructField.Name
:字段名。StructField.Type
:字段类型。StructField.Tag
:标签(如 JSON 标签)。StructField.Anonymous
:是否为匿名字段。
FieldByName(name)
根据字段名返回StructField
Elem
如果类型是指针,返回它指向的类型- 必须作用在指针、数组、切片、映射、通道上。如果对非指针类型调用
Elem()
,会panic。
- 必须作用在指针、数组、切片、映射、通道上。如果对非指针类型调用
- Value
reflect.ValueOf(v)
NumField()
返回结构体的字段数量Field(i int)
返回第 i 个字段的Value
FieldByName(name)
根据字段名返回字段的Value
Elem()
如果变量是指针,返回其指向的值CanSet()
判断变量是否可以被修改,true即为可修改Set()
设置变量的值(需要变量是可修改的,CanSet()
返回true)SetInt()
、SetString()
设置整数或字符串字段的值
举例
import (
"fmt"
"reflect"
)
type Name struct {
NickName string
}
type Person struct {
Name Name
Age int
}
func printReflectionInfo(i interface{}) {
t := reflect.TypeOf(i)
v := reflect.ValueOf(i)
fmt.Println("Type:", t)
fmt.Println("Type.Name:", t.Name())
fmt.Println("Type.Kind:", t.Kind())
fmt.Println("Type.NumField:", t.NumField())
//fmt.Println("Type.Elem:", t.Elem())
fmt.Println("Value:", v)
fmt.Println("Value.NumField:", v.NumField())
fmt.Println("Value.CanSet:", v.CanSet())
//fmt.Println("Value.Elem:", v.Elem())
if t.Kind() == reflect.Struct {
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
value := v.Field(i)
fmt.Printf("FieldName: %s, Type: %v, Value: %v, Kind: %v\n", field.Name, field.Type, value, value.Kind())
}
}
}
func main() {
p := Person{Name: Name{NickName: "Alice"}, Age: 30}
printReflectionInfo(p)
}
输出
Type: main.Person
Type.Name: Person
Type.Kind: struct
Type.NumField: 2
Value: {{Alice} 30}
Value.NumField: 2
Value.CanSet: false
FieldName: Name, Type: main.Name, Value: {Alice}, Kind: struct
FieldName: Age, Type: int, Value: 30, Kind: int