1.不知道接口调用哪个函数,根据传入参数在运行时确定调用的具体接口,这种需要对函数或方法反射
func bridge(funcPtr interface{}, args ...interface{})
例如以上这种桥接模式,第一个参数funcPtr以接口的形式传入函数指针,函数参数args以可变参数的形式传入,bridge函数中可以用反射来动态执行funcPtr函数
2.对结构体序列化时,如果结构体有指定Tag,也会使用到反射生成对应的字符串。
1.reflect.TypeOf(变量名),获取变量的类型,返回reflect.Type类型
2.reflect.ValueOf(变量名),获取变量的值,返回reflect.Value类型reflect.Value是一个结构体类型。通过reflect.Value,可以获取到关于该变量的很多信息。
3.变量,intface{}和reflect.Value是可以相互转换的,这点在实际开发中,会经常使用到
编写一个案例,演示对(基本数据类型,interface{},reflect.Value)进行反射的基本操作
package mainimport ("fmt""reflect"
)//专门演示反射
func reflectTest01(b interface{}) {//通过反射获取的传入的变量type,kind,值//1.现获取到reflect.TyperType := reflect.TypeOf(b)fmt.Println("rType=", rType)//2.获取到reflect.ValuerVal := reflect.ValueOf(b)n2 := 2 + rVal.Int() //此处的Int()表示拿到真正的valuefmt.Println("n2=", n2)fmt.Printf("rVal=5=%v rVal type=%T\n", rVal, rVal)//3、将rVal转换成interface{}iV := rVal.Interface()//将interface{}通过断言转化成需要的类型num2 := iV.(int)fmt.Println("num2=", num2)
}func main() {//编写一个案例//编写一个案例,演示对(基本数据类型,interface{},reflect.Value)进行反射的基本操作//先定义一个intvar num int = 100reflectTest01(num)
}
/*
rType= int
n2= 102
rVal=5=100 rVal type=reflect.Value
num2= 100
*/
编写一个案例,演示对(结构体类型,interface{},reflect.Value)进行反射的节本操作
package mainimport ("fmt""reflect"
)//演示对结构体的反射
func reflectTest(b interface{}) {rTyp := reflect.TypeOf(b)fmt.Println("rType=", rTyp)rVal := reflect.ValueOf(b)iV := rVal.Interface()fmt.Printf("iv=%v iV type=%T", iV, iV)
}type Student struct {Name stringAge int
}func main() {//定义一个student实例stu := Student{Name: "kunkun",Age: 25,}reflectTest(stu)
}
//rType= main.Student
//iv={kunkun 25} iV type=main.Student
1.reflect.Value.Kind,获取变量的类别,返回的是一个常量
2.Type是类型,Kind是类别,Type和Kind可能是相同的,也可能是不同的
比如:var num int = 10 num 的Type是int,Kind也是int
比如:var stu Student stu的Type是包名.Student,Kind是struct
3.使用反射的方式来获取变量的值(并返回对应的类型),要求数据类型匹配,比如x是int,那么就应该使用reflect.Value(x).int(),而不能使用其他的,否则报panic
5.通过反射的来修改变量,注意当使用SetXxx方法来设置需要通过对应的指针类型来完成,这样才能改变传入的变量的值,同样需要使用到reflect.Value.Elem()方法
package mainimport ("fmt""reflect"
)//通过反射,修改num int的值
//修改student的值func reflect01(b interface{}) {//获取到reflect.ValuerVal := reflect.ValueOf(b)rVal.Elem().SetInt(20)}func main() {var num int = 10reflect01(&num)fmt.Println("num=", num)
}
//rVal.Elem()用于获取指针指向变量,类似
//var num = 10
//var b *int =&num
//*b = 3//num = 20
1.使用反射来遍历结构体的字段,调用结构体的方法,并获取结构体标签的值
package mainimport ("fmt""reflect"
)//定义了一个Monster结构体
type Monster struct {Name string `json:"name"`Age int `json:"age"`Score float32Sex string
}//方法,显示s的值
func (s Monster) print() {fmt.Println("---start---")fmt.Println(s)fmt.Println("---end---")
}//方法,返回两个数的和
func (s Monster) GetSum(n1, n2 int) int {return n1 + n2
}//方法,接受四个值,给s赋值
func (s Monster) Set(name string, age int, score float32, sex string) {s.Name = names.Age = ages.Score = scores.Sex = sex
}func TestStruct(a interface{}) {//获取reflect.Type类型typ := reflect.TypeOf(a)//获取reflect.Value类型val := reflect.ValueOf(a)//获取到a对应的类型kd := val.Kind()//如果传入的不是struct,就退出if kd != reflect.Struct {fmt.Println("expect struct")return}//获取到该结构体有几个字段num := val.NumField()fmt.Printf("struct has %d fields\n", num)for i := 0; i < num; i++ {fmt.Printf("Field %d: 值为=%v\n", i, val.Field(i))//获取到struct标签,注意需要通过reflect.Type来获取tag标签的值tagVal := typ.Field(i).Tag.Get("json")if tagVal != "" {fmt.Printf("Field %d: tag为=%v\n", i, tagVal)}}numOfMethod := val.NumMethod()fmt.Printf("struct had %d methods\n", numOfMethod)//var params []reflect.Value//方法的排序默认是按照函数名的排序 (ASSCII码)val.Method(1).Call(nil)//调用结构体的第一个方法var params []reflect.Valueparams = append(params, reflect.ValueOf(10))params = append(params, reflect.ValueOf(40))res := val.Method(0).Call(params) //传入的参数是[]reflect.Valuefmt.Println("res=", res[0].Int()) //返回结果,返回的结果是[]reflect.Value
}
func main() {//创建了一个Monster实例var a Monster = Monster{Name: "kunkun",Age: 25,Score: 30.8,}//将Monster实例传递给TestStruct函数TestStruct(a)
}