968 lines
24 KiB
Go
968 lines
24 KiB
Go
/*
|
||
01-reflection.go - Go 语言反射详解
|
||
|
||
学习目标:
|
||
1. 理解反射的概念和原理
|
||
2. 掌握 reflect 包的基本使用
|
||
3. 学会反射的类型和值操作
|
||
4. 了解反射的应用场景
|
||
5. 掌握反射的最佳实践和注意事项
|
||
|
||
知识点:
|
||
- 反射的基本概念
|
||
- reflect.Type 和 reflect.Value
|
||
- 类型检查和转换
|
||
- 结构体字段和方法的反射
|
||
- 反射的性能考虑
|
||
- 反射的实际应用
|
||
*/
|
||
|
||
package main
|
||
|
||
import (
|
||
"fmt"
|
||
"reflect"
|
||
"strconv"
|
||
"strings"
|
||
"time"
|
||
)
|
||
|
||
func main() {
|
||
fmt.Println("=== Go 语言反射详解 ===\\n")
|
||
|
||
// 演示反射的基本概念
|
||
demonstrateReflectionBasics()
|
||
|
||
// 演示类型反射
|
||
demonstrateTypeReflection()
|
||
|
||
// 演示值反射
|
||
demonstrateValueReflection()
|
||
|
||
// 演示结构体反射
|
||
demonstrateStructReflection()
|
||
|
||
// 演示方法反射
|
||
demonstrateMethodReflection()
|
||
|
||
// 演示反射的实际应用
|
||
demonstratePracticalApplications()
|
||
|
||
// 演示反射的最佳实践
|
||
demonstrateBestPractices()
|
||
}
|
||
|
||
// demonstrateReflectionBasics 演示反射的基本概念
|
||
func demonstrateReflectionBasics() {
|
||
fmt.Println("1. 反射的基本概念:")
|
||
|
||
// 反射的基本概念
|
||
fmt.Printf(" 反射的基本概念:\\n")
|
||
fmt.Printf(" - 反射是程序在运行时检查自身结构的能力\\n")
|
||
fmt.Printf(" - Go 通过 reflect 包提供反射功能\\n")
|
||
fmt.Printf(" - 反射基于接口的动态类型信息\\n")
|
||
fmt.Printf(" - 主要包括类型反射和值反射\\n")
|
||
fmt.Printf(" - 反射遵循 Go 的类型系统规则\\n")
|
||
|
||
// 反射的核心类型
|
||
fmt.Printf(" 反射的核心类型:\\n")
|
||
fmt.Printf(" - reflect.Type: 表示类型信息\\n")
|
||
fmt.Printf(" - reflect.Value: 表示值信息\\n")
|
||
fmt.Printf(" - reflect.Kind: 表示基础类型种类\\n")
|
||
|
||
// 基本反射示例
|
||
fmt.Printf(" 基本反射示例:\\n")
|
||
|
||
var x interface{} = 42
|
||
|
||
// 获取类型信息
|
||
t := reflect.TypeOf(x)
|
||
fmt.Printf(" 类型: %v\\n", t)
|
||
fmt.Printf(" 类型名称: %s\\n", t.Name())
|
||
fmt.Printf(" 类型种类: %v\\n", t.Kind())
|
||
|
||
// 获取值信息
|
||
v := reflect.ValueOf(x)
|
||
fmt.Printf(" 值: %v\\n", v)
|
||
fmt.Printf(" 值的类型: %v\\n", v.Type())
|
||
fmt.Printf(" 值的种类: %v\\n", v.Kind())
|
||
fmt.Printf(" 值的接口: %v\\n", v.Interface())
|
||
|
||
// 不同类型的反射
|
||
fmt.Printf(" 不同类型的反射:\\n")
|
||
|
||
values := []interface{}{
|
||
42,
|
||
"hello",
|
||
3.14,
|
||
true,
|
||
[]int{1, 2, 3},
|
||
map[string]int{"a": 1},
|
||
Person{Name: "Alice", Age: 30},
|
||
}
|
||
|
||
for i, val := range values {
|
||
t := reflect.TypeOf(val)
|
||
v := reflect.ValueOf(val)
|
||
fmt.Printf(" 值%d: %v (类型: %v, 种类: %v)\\n",
|
||
i+1, val, t, v.Kind())
|
||
}
|
||
|
||
fmt.Println()
|
||
}
|
||
|
||
// demonstrateTypeReflection 演示类型反射
|
||
func demonstrateTypeReflection() {
|
||
fmt.Println("2. 类型反射:")
|
||
|
||
// 基本类型反射
|
||
fmt.Printf(" 基本类型反射:\\n")
|
||
|
||
var i int = 42
|
||
var s string = "hello"
|
||
var f float64 = 3.14
|
||
var b bool = true
|
||
|
||
types := []interface{}{i, s, f, b}
|
||
for _, val := range types {
|
||
t := reflect.TypeOf(val)
|
||
fmt.Printf(" %v: 名称=%s, 种类=%v, 大小=%d字节\\n",
|
||
val, t.Name(), t.Kind(), t.Size())
|
||
}
|
||
|
||
// 复合类型反射
|
||
fmt.Printf(" 复合类型反射:\\n")
|
||
|
||
// 切片类型
|
||
slice := []int{1, 2, 3}
|
||
sliceType := reflect.TypeOf(slice)
|
||
fmt.Printf(" 切片类型: %v\\n", sliceType)
|
||
fmt.Printf(" 元素类型: %v\\n", sliceType.Elem())
|
||
fmt.Printf(" 是否为切片: %t\\n", sliceType.Kind() == reflect.Slice)
|
||
|
||
// 映射类型
|
||
m := map[string]int{"a": 1, "b": 2}
|
||
mapType := reflect.TypeOf(m)
|
||
fmt.Printf(" 映射类型: %v\\n", mapType)
|
||
fmt.Printf(" 键类型: %v\\n", mapType.Key())
|
||
fmt.Printf(" 值类型: %v\\n", mapType.Elem())
|
||
|
||
// 指针类型
|
||
var p *int = &i
|
||
ptrType := reflect.TypeOf(p)
|
||
fmt.Printf(" 指针类型: %v\\n", ptrType)
|
||
fmt.Printf(" 指向类型: %v\\n", ptrType.Elem())
|
||
fmt.Printf(" 是否为指针: %t\\n", ptrType.Kind() == reflect.Ptr)
|
||
|
||
// 函数类型
|
||
fn := func(int, string) bool { return true }
|
||
fnType := reflect.TypeOf(fn)
|
||
fmt.Printf(" 函数类型: %v\\n", fnType)
|
||
fmt.Printf(" 参数个数: %d\\n", fnType.NumIn())
|
||
fmt.Printf(" 返回值个数: %d\\n", fnType.NumOut())
|
||
|
||
for i := 0; i < fnType.NumIn(); i++ {
|
||
fmt.Printf(" 参数%d类型: %v\\n", i, fnType.In(i))
|
||
}
|
||
|
||
for i := 0; i < fnType.NumOut(); i++ {
|
||
fmt.Printf(" 返回值%d类型: %v\\n", i, fnType.Out(i))
|
||
}
|
||
|
||
// 通道类型
|
||
ch := make(chan int)
|
||
chType := reflect.TypeOf(ch)
|
||
fmt.Printf(" 通道类型: %v\\n", chType)
|
||
fmt.Printf(" 通道方向: %v\\n", chType.ChanDir())
|
||
fmt.Printf(" 元素类型: %v\\n", chType.Elem())
|
||
|
||
fmt.Println()
|
||
}
|
||
|
||
// demonstrateValueReflection 演示值反射
|
||
func demonstrateValueReflection() {
|
||
fmt.Println("3. 值反射:")
|
||
|
||
// 基本值操作
|
||
fmt.Printf(" 基本值操作:\\n")
|
||
|
||
var x interface{} = 42
|
||
v := reflect.ValueOf(x)
|
||
|
||
fmt.Printf(" 原始值: %v\\n", v.Interface())
|
||
fmt.Printf(" 整数值: %d\\n", v.Int())
|
||
fmt.Printf(" 是否有效: %t\\n", v.IsValid())
|
||
fmt.Printf(" 是否为零值: %t\\n", v.IsZero())
|
||
|
||
// 值的修改
|
||
fmt.Printf(" 值的修改:\\n")
|
||
|
||
var y int = 100
|
||
v = reflect.ValueOf(&y) // 需要传递指针才能修改
|
||
if v.Kind() == reflect.Ptr && v.Elem().CanSet() {
|
||
v.Elem().SetInt(200)
|
||
fmt.Printf(" 修改后的值: %d\\n", y)
|
||
}
|
||
|
||
// 字符串值操作
|
||
var str string = "hello"
|
||
v = reflect.ValueOf(&str)
|
||
if v.Kind() == reflect.Ptr && v.Elem().CanSet() {
|
||
v.Elem().SetString("world")
|
||
fmt.Printf(" 修改后的字符串: %s\\n", str)
|
||
}
|
||
|
||
// 切片值操作
|
||
fmt.Printf(" 切片值操作:\\n")
|
||
|
||
slice := []int{1, 2, 3}
|
||
v = reflect.ValueOf(slice)
|
||
|
||
fmt.Printf(" 切片长度: %d\\n", v.Len())
|
||
fmt.Printf(" 切片容量: %d\\n", v.Cap())
|
||
|
||
// 访问切片元素
|
||
for i := 0; i < v.Len(); i++ {
|
||
elem := v.Index(i)
|
||
fmt.Printf(" 元素[%d]: %v\\n", i, elem.Interface())
|
||
}
|
||
|
||
// 映射值操作
|
||
fmt.Printf(" 映射值操作:\\n")
|
||
|
||
m := map[string]int{"a": 1, "b": 2, "c": 3}
|
||
v = reflect.ValueOf(m)
|
||
|
||
fmt.Printf(" 映射长度: %d\\n", v.Len())
|
||
|
||
// 遍历映射
|
||
for _, key := range v.MapKeys() {
|
||
value := v.MapIndex(key)
|
||
fmt.Printf(" %v: %v\\n", key.Interface(), value.Interface())
|
||
}
|
||
|
||
// 设置映射值
|
||
v.SetMapIndex(reflect.ValueOf("d"), reflect.ValueOf(4))
|
||
fmt.Printf(" 添加元素后: %v\\n", m)
|
||
|
||
// 创建新值
|
||
fmt.Printf(" 创建新值:\\n")
|
||
|
||
// 创建新的整数值
|
||
newInt := reflect.New(reflect.TypeOf(0))
|
||
newInt.Elem().SetInt(999)
|
||
fmt.Printf(" 新创建的整数: %v\\n", newInt.Elem().Interface())
|
||
|
||
// 创建新的切片
|
||
sliceType := reflect.SliceOf(reflect.TypeOf(0))
|
||
newSlice := reflect.MakeSlice(sliceType, 3, 5)
|
||
for i := 0; i < newSlice.Len(); i++ {
|
||
newSlice.Index(i).SetInt(int64(i * 10))
|
||
}
|
||
fmt.Printf(" 新创建的切片: %v\\n", newSlice.Interface())
|
||
|
||
fmt.Println()
|
||
}
|
||
|
||
// demonstrateStructReflection 演示结构体反射
|
||
func demonstrateStructReflection() {
|
||
fmt.Println("4. 结构体反射:")
|
||
|
||
// 结构体类型信息
|
||
fmt.Printf(" 结构体类型信息:\\n")
|
||
|
||
person := Person{
|
||
Name: "Alice",
|
||
Age: 30,
|
||
Email: "alice@example.com",
|
||
}
|
||
|
||
t := reflect.TypeOf(person)
|
||
v := reflect.ValueOf(person)
|
||
|
||
fmt.Printf(" 结构体名称: %s\\n", t.Name())
|
||
fmt.Printf(" 字段数量: %d\\n", t.NumField())
|
||
|
||
// 遍历结构体字段
|
||
fmt.Printf(" 遍历结构体字段:\\n")
|
||
|
||
for i := 0; i < t.NumField(); i++ {
|
||
field := t.Field(i)
|
||
value := v.Field(i)
|
||
|
||
fmt.Printf(" 字段%d: %s (类型: %v, 值: %v)\\n",
|
||
i, field.Name, field.Type, value.Interface())
|
||
|
||
// 检查字段标签
|
||
if tag := field.Tag; tag != "" {
|
||
fmt.Printf(" 标签: %s\\n", tag)
|
||
if jsonTag := tag.Get("json"); jsonTag != "" {
|
||
fmt.Printf(" JSON标签: %s\\n", jsonTag)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 按名称访问字段
|
||
fmt.Printf(" 按名称访问字段:\\n")
|
||
|
||
nameField := v.FieldByName("Name")
|
||
if nameField.IsValid() {
|
||
fmt.Printf(" Name字段值: %v\\n", nameField.Interface())
|
||
}
|
||
|
||
// 修改结构体字段
|
||
fmt.Printf(" 修改结构体字段:\\n")
|
||
|
||
// 需要使用指针才能修改
|
||
v = reflect.ValueOf(&person)
|
||
if v.Kind() == reflect.Ptr {
|
||
v = v.Elem() // 获取指针指向的值
|
||
|
||
nameField = v.FieldByName("Name")
|
||
if nameField.CanSet() {
|
||
nameField.SetString("Bob")
|
||
fmt.Printf(" 修改后的Name: %s\\n", person.Name)
|
||
}
|
||
|
||
ageField := v.FieldByName("Age")
|
||
if ageField.CanSet() {
|
||
ageField.SetInt(35)
|
||
fmt.Printf(" 修改后的Age: %d\\n", person.Age)
|
||
}
|
||
}
|
||
|
||
// 嵌套结构体
|
||
fmt.Printf(" 嵌套结构体:\\n")
|
||
|
||
employee := Employee{
|
||
Person: Person{Name: "Charlie", Age: 28},
|
||
Title: "Developer",
|
||
Salary: 80000,
|
||
}
|
||
|
||
t = reflect.TypeOf(employee)
|
||
v = reflect.ValueOf(employee)
|
||
|
||
fmt.Printf(" 嵌套结构体字段数: %d\\n", t.NumField())
|
||
|
||
for i := 0; i < t.NumField(); i++ {
|
||
field := t.Field(i)
|
||
value := v.Field(i)
|
||
|
||
fmt.Printf(" 字段%d: %s (类型: %v)\\n", i, field.Name, field.Type)
|
||
|
||
// 如果是嵌套结构体,进一步展开
|
||
if field.Type.Kind() == reflect.Struct {
|
||
fmt.Printf(" 嵌套字段:\\n")
|
||
nestedValue := value
|
||
nestedType := field.Type
|
||
|
||
for j := 0; j < nestedType.NumField(); j++ {
|
||
nestedField := nestedType.Field(j)
|
||
nestedFieldValue := nestedValue.Field(j)
|
||
fmt.Printf(" %s: %v\\n", nestedField.Name, nestedFieldValue.Interface())
|
||
}
|
||
} else {
|
||
fmt.Printf(" 值: %v\\n", value.Interface())
|
||
}
|
||
}
|
||
|
||
fmt.Println()
|
||
}
|
||
|
||
// demonstrateMethodReflection 演示方法反射
|
||
func demonstrateMethodReflection() {
|
||
fmt.Println("5. 方法反射:")
|
||
|
||
// 方法信息
|
||
fmt.Printf(" 方法信息:\\n")
|
||
|
||
person := &Person{Name: "David", Age: 25}
|
||
t := reflect.TypeOf(person)
|
||
v := reflect.ValueOf(person)
|
||
|
||
fmt.Printf(" 方法数量: %d\\n", t.NumMethod())
|
||
|
||
// 遍历方法
|
||
for i := 0; i < t.NumMethod(); i++ {
|
||
method := t.Method(i)
|
||
fmt.Printf(" 方法%d: %s (类型: %v)\\n", i, method.Name, method.Type)
|
||
}
|
||
|
||
// 调用方法
|
||
fmt.Printf(" 调用方法:\\n")
|
||
|
||
// 按名称获取方法
|
||
greetMethod := v.MethodByName("Greet")
|
||
if greetMethod.IsValid() {
|
||
// 调用无参数方法
|
||
result := greetMethod.Call(nil)
|
||
if len(result) > 0 {
|
||
fmt.Printf(" Greet方法返回: %v\\n", result[0].Interface())
|
||
}
|
||
}
|
||
|
||
// 调用带参数的方法
|
||
setAgeMethod := v.MethodByName("SetAge")
|
||
if setAgeMethod.IsValid() {
|
||
args := []reflect.Value{reflect.ValueOf(30)}
|
||
setAgeMethod.Call(args)
|
||
fmt.Printf(" 调用SetAge后,年龄: %d\\n", person.Age)
|
||
}
|
||
|
||
// 调用带返回值的方法
|
||
getInfoMethod := v.MethodByName("GetInfo")
|
||
if getInfoMethod.IsValid() {
|
||
result := getInfoMethod.Call(nil)
|
||
if len(result) > 0 {
|
||
fmt.Printf(" GetInfo方法返回: %v\\n", result[0].Interface())
|
||
}
|
||
}
|
||
|
||
// 函数值的反射调用
|
||
fmt.Printf(" 函数值的反射调用:\\n")
|
||
|
||
fn := func(a, b int) int {
|
||
return a + b
|
||
}
|
||
|
||
fnValue := reflect.ValueOf(fn)
|
||
args := []reflect.Value{
|
||
reflect.ValueOf(10),
|
||
reflect.ValueOf(20),
|
||
}
|
||
|
||
result := fnValue.Call(args)
|
||
fmt.Printf(" 函数调用结果: %v\\n", result[0].Interface())
|
||
|
||
// 方法集的检查
|
||
fmt.Printf(" 方法集的检查:\\n")
|
||
|
||
// 检查类型是否实现了某个接口
|
||
stringerType := reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
|
||
personType := reflect.TypeOf(person)
|
||
|
||
fmt.Printf(" Person是否实现Stringer接口: %t\\n",
|
||
personType.Implements(stringerType))
|
||
|
||
fmt.Println()
|
||
}
|
||
|
||
// demonstratePracticalApplications 演示反射的实际应用
|
||
func demonstratePracticalApplications() {
|
||
fmt.Println("6. 反射的实际应用:")
|
||
|
||
// 应用1: JSON 序列化
|
||
fmt.Printf(" 应用1 - JSON 序列化:\\n")
|
||
|
||
person := Person{
|
||
Name: "Eve",
|
||
Age: 32,
|
||
Email: "eve@example.com",
|
||
}
|
||
|
||
jsonStr := structToJSON(person)
|
||
fmt.Printf(" JSON序列化结果: %s\\n", jsonStr)
|
||
|
||
// 应用2: 结构体复制
|
||
fmt.Printf(" 应用2 - 结构体复制:\\n")
|
||
|
||
original := Person{Name: "Frank", Age: 40}
|
||
copied := copyStruct(original).(Person)
|
||
|
||
fmt.Printf(" 原始结构体: %+v\\n", original)
|
||
fmt.Printf(" 复制结构体: %+v\\n", copied)
|
||
|
||
// 应用3: 结构体比较
|
||
fmt.Printf(" 应用3 - 结构体比较:\\n")
|
||
|
||
person1 := Person{Name: "Grace", Age: 28}
|
||
person2 := Person{Name: "Grace", Age: 28}
|
||
person3 := Person{Name: "Henry", Age: 30}
|
||
|
||
fmt.Printf(" person1 == person2: %t\\n", deepEqual(person1, person2))
|
||
fmt.Printf(" person1 == person3: %t\\n", deepEqual(person1, person3))
|
||
|
||
// 应用4: 配置映射
|
||
fmt.Printf(" 应用4 - 配置映射:\\n")
|
||
|
||
config := map[string]interface{}{
|
||
"Name": "Iris",
|
||
"Age": 26,
|
||
"Email": "iris@example.com",
|
||
}
|
||
|
||
var configPerson Person
|
||
mapToStruct(config, &configPerson)
|
||
fmt.Printf(" 配置映射结果: %+v\\n", configPerson)
|
||
|
||
// 应用5: 验证器
|
||
fmt.Printf(" 应用5 - 验证器:\\n")
|
||
|
||
validPerson := Person{Name: "Jack", Age: 25, Email: "jack@example.com"}
|
||
invalidPerson := Person{Name: "", Age: -5, Email: "invalid"}
|
||
|
||
fmt.Printf(" 有效Person验证: %t\\n", validateStruct(validPerson))
|
||
fmt.Printf(" 无效Person验证: %t\\n", validateStruct(invalidPerson))
|
||
|
||
// 应用6: ORM 映射
|
||
fmt.Printf(" 应用6 - ORM 映射:\\n")
|
||
|
||
tableName := getTableName(Person{})
|
||
columns := getColumns(Person{})
|
||
|
||
fmt.Printf(" 表名: %s\\n", tableName)
|
||
fmt.Printf(" 列名: %v\\n", columns)
|
||
|
||
fmt.Println()
|
||
}
|
||
|
||
// demonstrateBestPractices 演示反射的最佳实践
|
||
func demonstrateBestPractices() {
|
||
fmt.Println("7. 反射的最佳实践:")
|
||
|
||
// 最佳实践原则
|
||
fmt.Printf(" 最佳实践原则:\\n")
|
||
fmt.Printf(" 1. 谨慎使用反射,优先考虑类型安全的方案\\n")
|
||
fmt.Printf(" 2. 缓存反射结果以提高性能\\n")
|
||
fmt.Printf(" 3. 进行充分的错误检查\\n")
|
||
fmt.Printf(" 4. 避免在热点路径使用反射\\n")
|
||
fmt.Printf(" 5. 使用接口而不是反射来实现多态\\n")
|
||
|
||
// 性能考虑
|
||
fmt.Printf(" 性能考虑:\\n")
|
||
|
||
// 性能测试示例
|
||
person := Person{Name: "Test", Age: 30}
|
||
|
||
// 直接访问 vs 反射访问
|
||
start := time.Now()
|
||
for i := 0; i < 100000; i++ {
|
||
_ = person.Name // 直接访问
|
||
}
|
||
directTime := time.Since(start)
|
||
|
||
start = time.Now()
|
||
v := reflect.ValueOf(person)
|
||
nameField := v.FieldByName("Name")
|
||
for i := 0; i < 100000; i++ {
|
||
_ = nameField.Interface() // 反射访问
|
||
}
|
||
reflectTime := time.Since(start)
|
||
|
||
fmt.Printf(" 直接访问耗时: %v\\n", directTime)
|
||
fmt.Printf(" 反射访问耗时: %v\\n", reflectTime)
|
||
fmt.Printf(" 性能差异: %.2fx\\n", float64(reflectTime)/float64(directTime))
|
||
|
||
// 错误处理
|
||
fmt.Printf(" 错误处理:\\n")
|
||
|
||
// 安全的反射操作
|
||
safeReflectOperation := func(obj interface{}, fieldName string) (interface{}, error) {
|
||
v := reflect.ValueOf(obj)
|
||
if v.Kind() != reflect.Struct {
|
||
return nil, fmt.Errorf("对象不是结构体")
|
||
}
|
||
|
||
field := v.FieldByName(fieldName)
|
||
if !field.IsValid() {
|
||
return nil, fmt.Errorf("字段 %s 不存在", fieldName)
|
||
}
|
||
|
||
return field.Interface(), nil
|
||
}
|
||
|
||
// 测试安全操作
|
||
result, err := safeReflectOperation(person, "Name")
|
||
if err != nil {
|
||
fmt.Printf(" 错误: %v\\n", err)
|
||
} else {
|
||
fmt.Printf(" 安全获取Name字段: %v\\n", result)
|
||
}
|
||
|
||
result, err = safeReflectOperation(person, "NonExistent")
|
||
if err != nil {
|
||
fmt.Printf(" 预期错误: %v\\n", err)
|
||
}
|
||
|
||
// 反射的替代方案
|
||
fmt.Printf(" 反射的替代方案:\\n")
|
||
fmt.Printf(" 1. 接口: 使用接口实现多态\\n")
|
||
fmt.Printf(" 2. 类型断言: 处理已知的有限类型集合\\n")
|
||
fmt.Printf(" 3. 代码生成: 编译时生成类型安全的代码\\n")
|
||
fmt.Printf(" 4. 泛型: Go 1.18+ 支持泛型编程\\n")
|
||
|
||
// 何时使用反射
|
||
fmt.Printf(" 何时使用反射:\\n")
|
||
fmt.Printf(" ✓ 序列化/反序列化库\\n")
|
||
fmt.Printf(" ✓ ORM 框架\\n")
|
||
fmt.Printf(" ✓ 配置映射\\n")
|
||
fmt.Printf(" ✓ 测试框架\\n")
|
||
fmt.Printf(" ✓ 依赖注入容器\\n")
|
||
fmt.Printf("\\n")
|
||
fmt.Printf(" ✗ 简单的类型转换\\n")
|
||
fmt.Printf(" ✗ 已知类型的操作\\n")
|
||
fmt.Printf(" ✗ 性能敏感的代码\\n")
|
||
fmt.Printf(" ✗ 可以用接口解决的问题\\n")
|
||
|
||
fmt.Println()
|
||
}
|
||
|
||
// ========== 类型定义 ==========
|
||
|
||
// Person 人员结构体
|
||
type Person struct {
|
||
Name string `json:"name" db:"name" validate:"required"`
|
||
Age int `json:"age" db:"age" validate:"min=0,max=150"`
|
||
Email string `json:"email" db:"email" validate:"email"`
|
||
}
|
||
|
||
// Greet 问候方法
|
||
func (p *Person) Greet() string {
|
||
return fmt.Sprintf("Hello, I'm %s", p.Name)
|
||
}
|
||
|
||
// SetAge 设置年龄
|
||
func (p *Person) SetAge(age int) {
|
||
p.Age = age
|
||
}
|
||
|
||
// GetInfo 获取信息
|
||
func (p *Person) GetInfo() string {
|
||
return fmt.Sprintf("Name: %s, Age: %d, Email: %s", p.Name, p.Age, p.Email)
|
||
}
|
||
|
||
// String 实现 Stringer 接口
|
||
func (p Person) String() string {
|
||
return fmt.Sprintf("Person{Name: %s, Age: %d}", p.Name, p.Age)
|
||
}
|
||
|
||
// Employee 员工结构体
|
||
type Employee struct {
|
||
Person
|
||
Title string `json:"title" db:"title"`
|
||
Salary float64 `json:"salary" db:"salary"`
|
||
}
|
||
|
||
// ========== 辅助函数 ==========
|
||
|
||
// structToJSON 将结构体转换为 JSON 字符串
|
||
func structToJSON(obj interface{}) string {
|
||
v := reflect.ValueOf(obj)
|
||
t := reflect.TypeOf(obj)
|
||
|
||
if v.Kind() != reflect.Struct {
|
||
return "{}"
|
||
}
|
||
|
||
var parts []string
|
||
for i := 0; i < v.NumField(); i++ {
|
||
field := t.Field(i)
|
||
value := v.Field(i)
|
||
|
||
// 获取 JSON 标签
|
||
jsonTag := field.Tag.Get("json")
|
||
if jsonTag == "" {
|
||
jsonTag = strings.ToLower(field.Name)
|
||
}
|
||
|
||
// 根据类型格式化值
|
||
var valueStr string
|
||
switch value.Kind() {
|
||
case reflect.String:
|
||
valueStr = fmt.Sprintf("\\\"%s\\\"", value.String())
|
||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||
valueStr = fmt.Sprintf("%d", value.Int())
|
||
case reflect.Float32, reflect.Float64:
|
||
valueStr = fmt.Sprintf("%.2f", value.Float())
|
||
case reflect.Bool:
|
||
valueStr = fmt.Sprintf("%t", value.Bool())
|
||
default:
|
||
valueStr = fmt.Sprintf("\\\"%v\\\"", value.Interface())
|
||
}
|
||
|
||
parts = append(parts, fmt.Sprintf("\\\"%s\\\": %s", jsonTag, valueStr))
|
||
}
|
||
|
||
return "{" + strings.Join(parts, ", ") + "}"
|
||
}
|
||
|
||
// copyStruct 复制结构体
|
||
func copyStruct(src interface{}) interface{} {
|
||
srcValue := reflect.ValueOf(src)
|
||
srcType := reflect.TypeOf(src)
|
||
|
||
if srcValue.Kind() != reflect.Struct {
|
||
return src
|
||
}
|
||
|
||
// 创建新的结构体实例
|
||
newValue := reflect.New(srcType).Elem()
|
||
|
||
// 复制所有字段
|
||
for i := 0; i < srcValue.NumField(); i++ {
|
||
srcField := srcValue.Field(i)
|
||
newField := newValue.Field(i)
|
||
|
||
if newField.CanSet() {
|
||
newField.Set(srcField)
|
||
}
|
||
}
|
||
|
||
return newValue.Interface()
|
||
}
|
||
|
||
// deepEqual 深度比较两个值
|
||
func deepEqual(a, b interface{}) bool {
|
||
va := reflect.ValueOf(a)
|
||
vb := reflect.ValueOf(b)
|
||
|
||
if va.Type() != vb.Type() {
|
||
return false
|
||
}
|
||
|
||
switch va.Kind() {
|
||
case reflect.Struct:
|
||
for i := 0; i < va.NumField(); i++ {
|
||
if !deepEqual(va.Field(i).Interface(), vb.Field(i).Interface()) {
|
||
return false
|
||
}
|
||
}
|
||
return true
|
||
case reflect.Slice:
|
||
if va.Len() != vb.Len() {
|
||
return false
|
||
}
|
||
for i := 0; i < va.Len(); i++ {
|
||
if !deepEqual(va.Index(i).Interface(), vb.Index(i).Interface()) {
|
||
return false
|
||
}
|
||
}
|
||
return true
|
||
case reflect.Map:
|
||
if va.Len() != vb.Len() {
|
||
return false
|
||
}
|
||
for _, key := range va.MapKeys() {
|
||
aVal := va.MapIndex(key)
|
||
bVal := vb.MapIndex(key)
|
||
if !bVal.IsValid() || !deepEqual(aVal.Interface(), bVal.Interface()) {
|
||
return false
|
||
}
|
||
}
|
||
return true
|
||
default:
|
||
return va.Interface() == vb.Interface()
|
||
}
|
||
}
|
||
|
||
// mapToStruct 将 map 映射到结构体
|
||
func mapToStruct(m map[string]interface{}, dst interface{}) error {
|
||
dstValue := reflect.ValueOf(dst)
|
||
if dstValue.Kind() != reflect.Ptr || dstValue.Elem().Kind() != reflect.Struct {
|
||
return fmt.Errorf("dst 必须是结构体指针")
|
||
}
|
||
|
||
dstValue = dstValue.Elem()
|
||
dstType := dstValue.Type()
|
||
|
||
for i := 0; i < dstValue.NumField(); i++ {
|
||
field := dstType.Field(i)
|
||
fieldValue := dstValue.Field(i)
|
||
|
||
if !fieldValue.CanSet() {
|
||
continue
|
||
}
|
||
|
||
// 从 map 中获取对应的值
|
||
if mapValue, ok := m[field.Name]; ok {
|
||
mapValueReflect := reflect.ValueOf(mapValue)
|
||
|
||
// 类型转换
|
||
if mapValueReflect.Type().ConvertibleTo(fieldValue.Type()) {
|
||
fieldValue.Set(mapValueReflect.Convert(fieldValue.Type()))
|
||
}
|
||
}
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// validateStruct 验证结构体
|
||
func validateStruct(obj interface{}) bool {
|
||
v := reflect.ValueOf(obj)
|
||
t := reflect.TypeOf(obj)
|
||
|
||
if v.Kind() != reflect.Struct {
|
||
return false
|
||
}
|
||
|
||
for i := 0; i < v.NumField(); i++ {
|
||
field := t.Field(i)
|
||
value := v.Field(i)
|
||
|
||
// 获取验证标签
|
||
validateTag := field.Tag.Get("validate")
|
||
if validateTag == "" {
|
||
continue
|
||
}
|
||
|
||
// 解析验证规则
|
||
rules := strings.Split(validateTag, ",")
|
||
for _, rule := range rules {
|
||
if !validateField(value, strings.TrimSpace(rule)) {
|
||
return false
|
||
}
|
||
}
|
||
}
|
||
|
||
return true
|
||
}
|
||
|
||
// validateField 验证单个字段
|
||
func validateField(value reflect.Value, rule string) bool {
|
||
switch rule {
|
||
case "required":
|
||
return !value.IsZero()
|
||
case "email":
|
||
if value.Kind() == reflect.String {
|
||
email := value.String()
|
||
return strings.Contains(email, "@") && strings.Contains(email, ".")
|
||
}
|
||
return false
|
||
default:
|
||
// 处理 min=0, max=150 等规则
|
||
if strings.HasPrefix(rule, "min=") {
|
||
minStr := strings.TrimPrefix(rule, "min=")
|
||
if min, err := strconv.Atoi(minStr); err == nil {
|
||
if value.Kind() == reflect.Int {
|
||
return value.Int() >= int64(min)
|
||
}
|
||
}
|
||
}
|
||
if strings.HasPrefix(rule, "max=") {
|
||
maxStr := strings.TrimPrefix(rule, "max=")
|
||
if max, err := strconv.Atoi(maxStr); err == nil {
|
||
if value.Kind() == reflect.Int {
|
||
return value.Int() <= int64(max)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return true
|
||
}
|
||
|
||
// getTableName 获取表名
|
||
func getTableName(obj interface{}) string {
|
||
t := reflect.TypeOf(obj)
|
||
if t.Kind() == reflect.Ptr {
|
||
t = t.Elem()
|
||
}
|
||
|
||
// 将结构体名转换为表名(简单的复数形式)
|
||
name := t.Name()
|
||
return strings.ToLower(name) + "s"
|
||
}
|
||
|
||
// getColumns 获取列名
|
||
func getColumns(obj interface{}) []string {
|
||
t := reflect.TypeOf(obj)
|
||
if t.Kind() == reflect.Ptr {
|
||
t = t.Elem()
|
||
}
|
||
|
||
var columns []string
|
||
for i := 0; i < t.NumField(); i++ {
|
||
field := t.Field(i)
|
||
|
||
// 获取数据库标签
|
||
dbTag := field.Tag.Get("db")
|
||
if dbTag != "" {
|
||
columns = append(columns, dbTag)
|
||
} else {
|
||
columns = append(columns, strings.ToLower(field.Name))
|
||
}
|
||
}
|
||
|
||
return columns
|
||
}
|
||
|
||
/*
|
||
运行这个程序:
|
||
go run 01-reflection.go
|
||
|
||
学习要点:
|
||
1. 反射是程序在运行时检查自身结构的能力
|
||
2. Go 通过 reflect 包提供反射功能
|
||
3. 反射主要包括类型反射和值反射
|
||
4. 反射可以用于序列化、ORM、配置映射等场景
|
||
5. 反射有性能开销,应该谨慎使用
|
||
|
||
反射的核心概念:
|
||
1. reflect.Type: 表示类型信息
|
||
2. reflect.Value: 表示值信息
|
||
3. reflect.Kind: 表示基础类型种类
|
||
4. 反射遵循 Go 的类型系统规则
|
||
5. 反射可以检查和修改值
|
||
|
||
类型反射:
|
||
1. 获取类型信息:reflect.TypeOf()
|
||
2. 类型名称和种类:Name(), Kind()
|
||
3. 复合类型:Elem(), Key(), In(), Out()
|
||
4. 结构体字段:NumField(), Field()
|
||
5. 方法信息:NumMethod(), Method()
|
||
|
||
值反射:
|
||
1. 获取值信息:reflect.ValueOf()
|
||
2. 值的访问:Interface(), Int(), String()
|
||
3. 值的修改:Set(), SetInt(), SetString()
|
||
4. 集合操作:Len(), Index(), MapIndex()
|
||
5. 创建新值:New(), MakeSlice(), MakeMap()
|
||
|
||
结构体反射:
|
||
1. 字段访问:Field(), FieldByName()
|
||
2. 字段信息:Name, Type, Tag
|
||
3. 字段修改:CanSet(), Set()
|
||
4. 标签解析:Tag.Get()
|
||
5. 嵌套结构体处理
|
||
|
||
方法反射:
|
||
1. 方法信息:Method(), MethodByName()
|
||
2. 方法调用:Call()
|
||
3. 方法类型:Type, NumIn(), NumOut()
|
||
4. 接口检查:Implements()
|
||
5. 方法集分析
|
||
|
||
实际应用场景:
|
||
1. JSON 序列化/反序列化
|
||
2. ORM 数据库映射
|
||
3. 配置文件映射
|
||
4. 结构体验证
|
||
5. 依赖注入
|
||
6. 测试框架
|
||
7. 代码生成工具
|
||
|
||
性能考虑:
|
||
1. 反射比直接访问慢很多
|
||
2. 缓存反射结果可以提高性能
|
||
3. 避免在热点路径使用反射
|
||
4. 考虑使用接口替代反射
|
||
5. 编译时代码生成是更好的选择
|
||
|
||
最佳实践:
|
||
1. 谨慎使用反射,优先考虑类型安全
|
||
2. 进行充分的错误检查
|
||
3. 缓存反射操作的结果
|
||
4. 使用接口实现多态
|
||
5. 考虑性能影响
|
||
6. 提供清晰的文档说明
|
||
|
||
注意事项:
|
||
1. 反射会破坏类型安全
|
||
2. 反射代码难以理解和维护
|
||
3. 反射错误只能在运行时发现
|
||
4. 反射会影响代码的可读性
|
||
5. 反射操作可能导致 panic
|
||
*/
|