1. 先看一个问题来引出反射
package main
import (
"fmt"
"encoding/json"
)
// 先看一个问题,引出反射的使用场景
type Monster struct {
Name string `json: "monsterName"`
Age int `json: "monsterAge"`
Sal float64 `json: "monsterSal"`
Sex string `json: "monsterSex"`
}
func main() {
m := Monster{
Name: "孙悟空",
Age: 5000,
Sal: 18888.999,
Sex: "男",
}
data,_ := json.Marshal(m)
fmt.Println("json result:",string(data))
}
问题1:
为什么序列化后的,key-val的key值是Tag值,而不是字段的名称,比如:不是Name而是monsterName
引出反射:学习完reflect后,回来解决
2.使用反射机制,编写函数的适配器,桥连接
要求如下:
1)定义了两个匿名函数
test1 := func(v1 int, v2 int) {
t.Log(v1,v2)
}
2)定义一个适配器函数用作统一处理接口,其大致结构如下:
bridge := func(call interface{},args...interface{}){
// 内容
}
// 实现调用test1对应的函数
bridge(test1,1,2)
// 实现调用test2对应的函数
bridge(test2,1,2,"test2")
3)要求使用反射机制完成(note: 学习reflect后来解决)'
3. 反射的基本介绍
1)反射可以在运行时动态获取变量的各种信息,比如变量的类型(type),类别(kind)
2)如果是结构体变量,还可以获取到结构体本身的信息(包括结构体的字段、方法)
3)通过反射,可以修改变量的值,可以调用关联的方法
4)使用反射,需要import ("reflect")
5)示意图:
4. 反射的应用场景
反射常见的应有场景有以下两种
1)不知道接口调用哪个函数,根据传入参数在运行时确定调用的具体接口,这种需要对函数或方法反射。例如:以下这种桥接模式。
第一个参数funcPtr以接口的形式传入函数指针,函数参数args以可变参数的形式传入,bridge函数中可以用反射来动态执行funcPtr函数
2)对结构体序列化时,如果结构体有指定的Tag,也会使用到反射生成对应的字符串
5.反射重要的函数和概念
1)reflect.TypeOf(变量名),获取变量的类型,返回reflect.Type类型
2)reflect.ValueOf(变量名),获取变量的值,返回reflect.Value类型reflect.Value是一个结构体类型。【看文档】,通过reflect.Value,可以获取到关于该变量的很多信息
3)变量、interface{} 和 reflect.Value 是可以相互转换的,在实际开发中,会经常使用到。
示意图如下:
6. 反射的快速入门
快速入门说明
1)请编写一个案例,演示对(基本数据类型、interface{}、reflect.Value)进行反射的基本操纵
代码演示:
package main
import (
"fmt"
"reflect"
)
// 专门演示反射
func reflectTest01(b interface{}) {
// 通过反射获取的传入的变量的type,kind值
// 1. 先获取到 reflect.Type
rTyp := reflect.TypeOf(b)
fmt.Println("rType=",rTyp)
// 2. 获取到 reflect.Value
rVal := reflect.ValueOf(b)
n2 := 2 + rVal.Int()
// rVal.Int()等价于
// rVal.Interface()
// rVal.(int)
fmt.Println("n2=",n2)
fmt.Printf("rVal=%v rVal type=%T\n",rVal,rVal)
// 下面我们将rVal转成interface{}
iV := rVal.Interface()
// 将interface{} 通过类型断言转成需要的类型
num2 := iV.(int)
fmt.Println("num2=",num2)
}
func main() {
// 请编写一个案例,演示对(基本数据类型,interface{},reflect.Value)进行反射的基本操作
// 1. 先定义一个int
var num int = 100
reflectTest01(num)
}
2)请编写一个案例,演示对(结构体类型、interface{}、reflect.Value)进行反射的基本操作
代码演示:
package main
import (
"fmt"
"reflect"
)
type Student struct{
Name string
Age int
}
type Monster struct{
Name string
Age int
}
// 专门演示反射【对结构体的反射】
func reflectTest02(b interface{}) {
// 通过反射获取的传入的变量 type,kind值
// 1. 先获取到 reflect.Type
rTyp := reflect.TypeOf(b)
fmt.Println("rType=",rTyp)
// 2. 获取到reflect.Value
rVal := reflect.ValueOf(b)
// 下面我们将 rVal 转成 interface{}
iV := rVal.Interface()
fmt.Printf("iv=%v iv type=%T\n",iV,iV)
fmt.Println(iV.(Student))
}
func main() {
// 演示对结构体的反射
// 1. 定义一个Student的结构体
stu := Student {
Name: "tom",
Age: 20,
}
reflectTest02(stu)
}