完成
This commit is contained in:
967
golang-learning/09-advanced/01-reflection.go
Normal file
967
golang-learning/09-advanced/01-reflection.go
Normal file
@@ -0,0 +1,967 @@
|
||||
/*
|
||||
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
|
||||
*/
|
Reference in New Issue
Block a user