Initial commit
This commit is contained in:
@@ -0,0 +1,410 @@
|
||||
# 1. 反射基础概念
|
||||
|
||||
- **定义**: 在程序运行时动态获取和操作变量信息的机制
|
||||
- **主要用途**:
|
||||
- 获取变量类型和值
|
||||
- 访问和修改结构体字段
|
||||
- 动态调用方法
|
||||
- 实现框架底层逻辑
|
||||
|
||||
# 2. 使用场景
|
||||
|
||||
- **适用场景**:
|
||||
- 开发框架和脚手架
|
||||
- 实现通用性工具
|
||||
- 处理未知类型的数据
|
||||
- **使用建议**:
|
||||
- 一般开发中谨慎使用
|
||||
- 反射操作性能开销较大
|
||||
- 代码复杂度会增加
|
||||
|
||||
# 3. 核心概念
|
||||
|
||||
## Type 和 Kind 的区别
|
||||
|
||||
```go
|
||||
// Type: 具体类型
|
||||
var user User = User{name: "Tom", age: 20}
|
||||
// Kind: 底层类型分类
|
||||
var num int = 18
|
||||
```
|
||||
|
||||
- **Type(类型)**:
|
||||
- 具体的数据类型
|
||||
- 例如: `User`, `Student`, `int64`
|
||||
|
||||
- **Kind(种类)**:
|
||||
- 类型的底层分类
|
||||
- 例如: `struct`, `int`, `string`
|
||||
|
||||
# 4. reflect 包核心功能
|
||||
|
||||
## 主要 API
|
||||
|
||||
```go
|
||||
// 获取类型信息
|
||||
typeInfo := reflect.TypeOf(变量)
|
||||
|
||||
// 获取值信息
|
||||
valueInfo := reflect.ValueOf(变量)
|
||||
```
|
||||
|
||||
## 常用操作
|
||||
|
||||
```go
|
||||
// 类型判断
|
||||
if typeInfo.Kind() == reflect.Struct {
|
||||
// 处理结构体
|
||||
}
|
||||
|
||||
// 获取/修改值
|
||||
if valueInfo.Kind() == reflect.Int {
|
||||
value := valueInfo.Int()
|
||||
valueInfo.Set(reflect.ValueOf(20))
|
||||
}
|
||||
```
|
||||
|
||||
# 5. 实际应用示例
|
||||
|
||||
## 结构体反射
|
||||
|
||||
```go
|
||||
type User struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
func inspectStruct(v interface{}) {
|
||||
t := reflect.TypeOf(v)
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
field := t.Field(i)
|
||||
fmt.Printf("字段名: %s, 类型: %s\n",
|
||||
field.Name, field.Type)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 方法反射
|
||||
|
||||
```go
|
||||
func (u User) SayHello(name string) {
|
||||
fmt.Printf("Hello, %s\n", name)
|
||||
}
|
||||
|
||||
// 通过反射调用方法
|
||||
func callMethod(v interface{}) {
|
||||
val := reflect.ValueOf(v)
|
||||
method := val.MethodByName("SayHello")
|
||||
args := []reflect.Value{reflect.ValueOf("Tom")}
|
||||
method.Call(args)
|
||||
}
|
||||
```
|
||||
|
||||
# 6. 性能考虑
|
||||
|
||||
- 反射操作比直接操作慢 10-100 倍
|
||||
- 建议在以下场景使用:
|
||||
- 框架开发
|
||||
- 配置解析
|
||||
- 序列化/反序列化
|
||||
- 避免在性能敏感代码中使用
|
||||
|
||||
# 7. 最佳实践
|
||||
|
||||
1. 优先使用类型断言代替反射
|
||||
2. 缓存反射结果避免重复操作
|
||||
3. 谨慎使用反射修改值
|
||||
4. 做好错误处理
|
||||
5. 编写清晰的文档说明
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// 反射
|
||||
/*
|
||||
Type : reflect.TypeOf(a) , 获取变量的类型
|
||||
Value :reflect.ValueOf(a) , 获取变量的值
|
||||
*/
|
||||
|
||||
func main() {
|
||||
// 正常编程定义变量
|
||||
var a int = 3
|
||||
fmt.Println("type", reflect.TypeOf(a))
|
||||
fmt.Println("value", reflect.ValueOf(a))
|
||||
|
||||
// 根据反射的值,来获取对象对应的类型和数值
|
||||
// 如果我们不知道这个对象的信息,我们可以通过这个对象拿到代码中的一切。
|
||||
// Value
|
||||
v := reflect.ValueOf(a) // string int User
|
||||
// Kind : 获取这个值的种类, 在反射中,所有数据类型判断都是使用种类。
|
||||
if v.Kind() == reflect.Float64 {
|
||||
fmt.Println(v.Float())
|
||||
}
|
||||
if v.Kind() == reflect.Int {
|
||||
fmt.Println(v.Int())
|
||||
}
|
||||
fmt.Println(v.Kind() == reflect.Float64)
|
||||
//fmt.Println(v.Type())
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
> 静态类型 & 动态类型
|
||||
|
||||
在反射过程中,编译的时候就知道变量类型的就是静态类型、如果在运行时候才知道类型的就是动态类型
|
||||
|
||||
静态类型:变量在声明时候给他赋予类型的
|
||||
|
||||
```go
|
||||
var name string // string是静态类型的
|
||||
var age int // int 是静态类型的
|
||||
```
|
||||
|
||||
动态类型:在运行的时候可能发生变化,主要考虑赋值问题
|
||||
|
||||
```go
|
||||
var A interface{} // interface{} 静态类型
|
||||
|
||||
A = 10 // interface{} 静态类型 动态类型 int
|
||||
A = "xuexiangban" // interface{} 静态类型 动态类型 string
|
||||
```
|
||||
|
||||
**为什么要用反射:**
|
||||
|
||||
1、我们需要编写一个函数,但是不知道函数传递给我的参数时什么?没约定好,传入的类型太多,这些类型不能统一表示,反射。
|
||||
|
||||
2、我们在某些使用,需要根据条件来判断具体使用哪个函数处理问题,根据用户的输入来决定,这时候就需要对函数的参数进行反射,在运行期间来动态处理。
|
||||
|
||||
**为什么不建议使用反射:**
|
||||
|
||||
1、和反射相关的代码,不方便阅读,开发中,代码可读性(指标)很重要
|
||||
|
||||
2、Go语言是静态类型的语言,编译器可以找出开发时候的错误,如果代码中有大量反射代码,随时可能存在安全问题,panic,项目就终止。
|
||||
|
||||
3、反射的性能很低,相对于正常的开发,至少慢2-3个数量级。项目关键位置低耗时,一定是不能使用反射的。更多时候使用约定。
|
||||
|
||||
# 反射获取变量信息
|
||||
|
||||
**实现拿到一个对象,还原它的本身结构信息**
|
||||
|
||||
reflect.TypeOf(v) : 获取变量的类型 Type
|
||||
|
||||
- Type.kind , 找到种类
|
||||
- Type.NumField(),找到里面字段的数量
|
||||
- Type.Filed(i)
|
||||
- Type.NumMethod(),找到里面方法的数量
|
||||
- Type.Method(i)
|
||||
|
||||
reflect.ValueOf(v) : 获取变量的值 Value
|
||||
|
||||
- Value.Field(i).Interface()
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Name string
|
||||
Age int
|
||||
Sex string
|
||||
}
|
||||
|
||||
func (user User) Say(msg string) {
|
||||
fmt.Println("User 说:", msg)
|
||||
}
|
||||
|
||||
// toString : 打印结构体信息
|
||||
func (user User) PrintInfo() {
|
||||
fmt.Printf("姓名:%s,年龄:%d,性别:%s\n", user.Name, user.Age, user.Sex)
|
||||
}
|
||||
|
||||
func main() {
|
||||
user := User{"kuangshen", 18, "男"}
|
||||
|
||||
reflectGetInfo(user)
|
||||
}
|
||||
|
||||
// 通过反射,获取变量的信息
|
||||
func reflectGetInfo(v interface{}) {
|
||||
// 1、获取参数的类型Type , 可能是用户自己定义的,但是Kind一定是内部类型struct
|
||||
getType := reflect.TypeOf(v)
|
||||
fmt.Println(getType.Name()) // 类型信息 User
|
||||
fmt.Println(getType.Kind()) // 找到上级的种类Kind struct
|
||||
|
||||
// 2、获取值
|
||||
getValue := reflect.ValueOf(v)
|
||||
fmt.Println("获取到value", getValue)
|
||||
|
||||
// 获取字段,通过Type扒出字段
|
||||
// Type.NumField() 获取这个类型中有几个字段 3
|
||||
// field(index) 得到字段的值
|
||||
for i := 0; i < getType.NumField(); i++ {
|
||||
field := getType.Field(i) // 类型
|
||||
value := getValue.Field(i).Interface() // value
|
||||
// 打印
|
||||
fmt.Printf("字段名:%s,字段类型:%s,字段值:%v\n", field.Name, field.Type, value)
|
||||
}
|
||||
|
||||
// 获取这个结构体的方法 , 获取方法的数量
|
||||
for i := 0; i < getType.NumMethod(); i++ {
|
||||
method := getType.Method(i)
|
||||
fmt.Printf("方法的名字:%s,方法类型:%s", method.Name, method.Type)
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
type User struct{
|
||||
Name string
|
||||
Age int
|
||||
Sex string
|
||||
}
|
||||
func (main.User) PrintInfo(){}
|
||||
func (main.User) Say(string)
|
||||
*/
|
||||
```
|
||||
|
||||
# 反射修改变量的值
|
||||
|
||||
vaule.CanSet
|
||||
|
||||
vaule.SetXXX
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// 反射设置变量的值
|
||||
func main() {
|
||||
|
||||
var num float64 = 3.14
|
||||
update(num)
|
||||
fmt.Println(num)
|
||||
|
||||
}
|
||||
func update(v any) {
|
||||
// 通过反射修改值,需要操作对象的指针,拿到地址,然后拿到指针对象
|
||||
pointer := reflect.ValueOf(&v)
|
||||
newValue := pointer.Elem()
|
||||
|
||||
fmt.Println("类型:", newValue.Type())
|
||||
fmt.Println("判断该类型是否可以修改:", newValue.CanSet())
|
||||
if newValue.Kind() == reflect.Float64 {
|
||||
// 通过反射对象给变量赋值
|
||||
newValue.SetFloat(2.21)
|
||||
}
|
||||
if newValue.Kind() == reflect.Int {
|
||||
// 通过反射对象给变量赋值
|
||||
newValue.SetFloat(2)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
修改结构体变量:通过属性名,来实现修改
|
||||
|
||||
```go
|
||||
func main() {
|
||||
user := User{"kuangshen", 18, "男"}
|
||||
|
||||
value := reflect.ValueOf(&user)
|
||||
if value.Kind() == reflect.Ptr {
|
||||
// 获取指针对象
|
||||
newValue := value.Elem()
|
||||
if newValue.CanSet() {
|
||||
// 如果是结构体:1、需要找到对象的结构体字段名
|
||||
newValue.FieldByName("Name").SetString("狂神")
|
||||
newValue.FieldByName("Age").SetInt(26)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println(user)
|
||||
|
||||
//reflectGetInfo(user)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
# 反射调用方法
|
||||
|
||||
> value.MethodByName("PrintInfo").Call(nil)
|
||||
>
|
||||
> // 参数构建
|
||||
>
|
||||
> args := make([]reflect.Value, 1)
|
||||
> args[0] = reflect.ValueOf("这反射来调用的")
|
||||
|
||||
通过反射调用user方法
|
||||
|
||||
```go
|
||||
user := User{"kuangshen", 18, "男"}
|
||||
|
||||
// 通过方法名,找到这个方法, 然后调用 Call() 方法来执行
|
||||
// 反射调用方法
|
||||
value := reflect.ValueOf(user)
|
||||
fmt.Printf("kind:%s,type:%s\n", value.Kind(), value.Type())
|
||||
value.MethodByName("PrintInfo").Call(nil) // 无参方法调用
|
||||
|
||||
// 有参方法调用
|
||||
args := make([]reflect.Value, 1)
|
||||
args[0] = reflect.ValueOf("这反射来调用的")
|
||||
value.MethodByName("Say").Call(args) // 无参方法调用
|
||||
```
|
||||
|
||||
# 反射调用函数
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// 反射调用函数 func
|
||||
func main() {
|
||||
// 通过函数名来进行反射
|
||||
// Kind func
|
||||
value1 := reflect.ValueOf(fun1)
|
||||
fmt.Println(value1.Kind(), value1.Type())
|
||||
value1.Call(nil)
|
||||
|
||||
value2 := reflect.ValueOf(fun2)
|
||||
fmt.Println(value2.Kind(), value2.Type())
|
||||
|
||||
args1 := make([]reflect.Value, 2)
|
||||
args1[0] = reflect.ValueOf(1)
|
||||
args1[1] = reflect.ValueOf("hahahhaha")
|
||||
value2.Call(args1)
|
||||
|
||||
vuale3 := reflect.ValueOf(fun3)
|
||||
fmt.Println(vuale3.Kind(), vuale3.Type())
|
||||
args2 := make([]reflect.Value, 2)
|
||||
args2[0] = reflect.ValueOf(1)
|
||||
args2[1] = reflect.ValueOf("hahahhaha")
|
||||
resultValue := vuale3.Call(args2)
|
||||
fmt.Println("返回值:", resultValue)
|
||||
}
|
||||
func fun1() {
|
||||
fmt.Println("fun1:无参")
|
||||
}
|
||||
func fun2(i int, s string) {
|
||||
fmt.Println("fun2:有参 i=", i, " s=", s)
|
||||
}
|
||||
func fun3(i int, s string) string {
|
||||
fmt.Println("fun3:有参有返回值 i=", i, " s=", s)
|
||||
return s
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user