|
3 | 3 | [反射原理](https://www.cnblogs.com/killianxu/p/18314594) |
4 | 4 |
|
5 | 5 | ## 是什么? |
6 | | -- 在计算机科学中,反射是指计算机程序在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力。用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为。 |
7 | | -- Go 语言提供了一种机制在运行时更新变量和检查它们的值、调用它们的方法,但是在编译时并不知道这些变量的具体类型,这称为反射机制。 |
| 6 | +- 在编译时并不知道这些变量的具体类型。 |
| 7 | +- 在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力。 |
8 | 8 | - 就是把类型元数据暴露给用户使用。 |
9 | 9 | ## 应用 |
10 | 10 | - 对象序列化(encoding/json) |
11 | 11 | - fmt 相关函数的实现 |
12 | 12 | - ORM |
| 13 | +- 依赖注入 |
13 | 14 |
|
14 | 15 | ## 如何实现反射 |
15 | 16 | Go语言反射是建立在Go类型系统和interface设计之上的。 |
16 | 17 | 在 reflect 包里定义了各种类型,实现了反射的各种函数,通过它们可以在运行时检测类型的信息、改变类型的值。 |
17 | 18 |
|
18 | 19 | ## 关键功能 |
19 | | -reflect包提供的功能比较多,但核心功能是把interface变量转化为反射类型对象reflect.Type和reflect.Value,并通过反射类型对象提供的功能,访问真实对象的方法和属性。 |
| 20 | +核心功能是把interface变量转化为反射类型对象reflect.Type和reflect.Value,并通过反射类型对象提供的功能,访问真实对象的方法和属性。 |
20 | 21 |
|
21 | 22 | ```go |
22 | 23 | type any = interface{} |
@@ -51,8 +52,41 @@ func (v Value) Interface() (i any) |
51 | 52 | ## DeepEqual 的实现只需要递归地调用 == 就可以比较两个变量是否是真的“深度”相等。 |
52 | 53 | 有一些异常情况:比如 func 类型是不可比较的类型,只有在两个 func 类型都是 nil 的情况下,才是“深度”相等;float 类型,由于精度的原因,也是不能使用 == 比较的;包含 func 类型或者 float 类型的 struct, interface, array 等。 |
53 | 54 |
|
54 | | -## TypeOf函数 |
55 | | -用于获取一个变量的类型信息。它接收一个空接口类型的参数,并返回一个reflect.Type接口类型的返回值。 |
| 55 | +### 1. 功能区别 |
56 | 56 |
|
57 | | -## ValueOf函数 |
58 | | -reflect.Value类型的,这是一个结构体类型,第一个字段存储反射变量的类型元数据指针,第二个字段存储数据地址,第三个字段是一个位标识符,存储反射值的一些描述信息,例如是否为指针,是否为方法,是否只读等等,通过会用reflect.ValueOf来拿到一个reflect.Value |
| 57 | +| 函数 | 作用 | 返回值类型 | |
| 58 | +|-----------------------|---------------------------------------------------------------------|------------------| |
| 59 | +| `reflect.TypeOf(obj)` | 获取 `obj` 的**类型信息**(如结构体名称、方法、字段等) | `reflect.Type` | |
| 60 | +| `reflect.ValueOf(obj)`| 获取 `obj` 的**值信息**(如实际存储的数据),并支持动态操作值(修改、调用方法) | `reflect.Value` | |
| 61 | + |
| 62 | +--- |
| 63 | + |
| 64 | +### 2. 返回对象的能力 |
| 65 | + |
| 66 | +#### **`reflect.Type`(通过 `TypeOf` 获取)** |
| 67 | +- **提供类型元信息**: |
| 68 | + - 类型名称(`Name()`) |
| 69 | + - 类型种类(`Kind()`,如 `int`、`struct`、`slice`) |
| 70 | + - 方法列表(`NumMethod()`、`Method(i)`) |
| 71 | + - 结构体字段信息(`NumField()`、`Field(i)`) |
| 72 | + - 是否实现某接口(`Implements(u Type)`) |
| 73 | +- **特性**: |
| 74 | + *仅用于读取类型信息,不可修改数据*。 |
| 75 | + |
| 76 | +#### **`reflect.Value`(通过 `ValueOf` 获取)** |
| 77 | +- **提供值操作能力**: |
| 78 | + - 获取实际值(`Interface()`) |
| 79 | + - 修改值(`Set()`、`SetInt()`,需满足可寻址性) |
| 80 | + - 调用方法(`Call()`) |
| 81 | + - 判断是否零值(`IsZero()`) |
| 82 | +- **可寻址性要求**: |
| 83 | + 必须通过指针获取 `Value` 才能修改值(例如 `Value.Elem()`)。 |
| 84 | + |
| 85 | +--- |
| 86 | + |
| 87 | +### 关键区别总结 |
| 88 | +| **维度** | `reflect.Type` | `reflect.Value` | |
| 89 | +|----------------|---------------------------------------------|----------------------------------------------| |
| 90 | +| **核心功能** | 类型元数据分析 | 值操作与动态行为 | |
| 91 | +| **数据修改** | ❌ 不可修改 | ✅ 可修改(需可寻址) | |
| 92 | +| **典型应用** | 检查结构体字段、接口实现 | 动态调用方法、序列化/反序列化、依赖注入 | |
0 commit comments