一、从案列场景引入反射
定义了两个函数test1和test2,定义一个适配器函数用作统一处理接口:
(1) 定义了两个函数
test1 := func(v1 int, v2 int) {
t.Log(v1, v2)
}
test2 := func(v1 int, v2 int, s string) {
t.Log(v1, v2, s)
}
(2) 定义一个适配器函数用作统一处理接口, 其大致结构如下:
bridge := func(call interface{
}, args ...interface{}) {
//内容
}
//实现调用test1对应的函数
bridge(test1, 1, 2)
//实现调用test2对应的函数
bridge(test2, 1, 2, "test2")
(3) 要求使用反射机制完成
package test
import (
"testing"
"reflect"
)
/*反射的最佳实践*/
/*
3) 定义了两个函数test1和test2,定义一个适配器函数用作统一处理接口【了解】:
(1) 定义了两个函数
test1 := func(v1 int, v2 int) {
t.Log(v1, v2)
}
test2 := func(v1 int, v2 int, s string) {
t.Log(v1, v2, s)
}
(2) 定义一个适配器函数用作统一处理接口, 其大致结构如下:
bridge := func(call interface{}, args ...interface{}) {
//内容
}
//实现调用test1对应的函数
bridge(test1, 1, 2)
//实现调用test2对应的函数
bridge(test2, 1, 2, "test2")
(3) 要求使用反射机制完成
*/
func TestReflectFunc(t *testing.T) {
call1 := func(v1 int, v2 int) {
t.Log(v1, v2)
}
call2 := func(v1 int, v2 int, s string) {
t.Log(v1, v2, s)
}
var (
function reflect.Value
inValue []reflect.Value
n int
)
bridge := func(call interface{}, args ...interface{}) {
n = len(args)
inValue = make([]reflect.Value, n)
for i := 0; i < n; i++ {
inValue[i] = reflect.ValueOf(args[i])
}
function = reflect.ValueOf(call)
function.Call(inValue)
}
bridge(call1, 1, 2)
bridge(call2, 1, 2, "test2")
}
二、反射的基本介绍
1、反射可以在运行时动态获取变量的各种信息, 比如变量的类型(type),类别(kind)
2、 如果是结构体变量,还可以获取到结构体本身的信息(包括结构体的字段、方法)
3、通过反射,可以修改变量的值,可以调用关联的方法。
4、使用反射,需要 import (“reflect”)
5、 示意图
三、反射的应用场景
1、反射常见应用场景有以下两种
不知道接口调用哪个函数,根据传入参数在运行时确定调用的具体接口,这种需要对函数或方法反射。例如以下这种桥接模式, 比如我前面提出问题。
第一个参数funcPtr以接口的形式传入函数指针,函数参数args以可变参数的形式传入,bridge函数中可以用反射来动态执行funcPtr函数
2、对结构体序列化时,如果结构体有指定Tag, 也会使用到反射生成对应的字符串。
四、反射重要的函数和概念
1、reflect.TypeOf(变量名),获取变量的类型,返回reflect.Type类型
2、reflect.ValueOf(变量名),获取变量的值,返回reflect.Value类型reflect.Value 是一个结构体类型。【看文档】, 通过reflect.Value,可以获取到关于该变量的很多信息
3、变量、interface{} 和 reflect.Value是可以相互转换的,这点在实际开发中,会经常使用到。
变量 interface{} 和reflect.Value()是可以相互转换的,
变量 interface{} 和valueOf()之间的转换
五、快速入门的案例
反射普通变量和结构体
//反射操作方法-基本数据类型float64
func reflectOper(b interf