反射基本介绍:

(1)反射可以在运行时动态获取变量的各种信息,比如变量的类型、类别;

(2)如果是结构体变量,还可以获取结构体本身的信息(包括结构体字段、方法);

(3)通过反射,可以修改变量的值,可以调用关联的方法;

(4)使用反射,需要Import "reflect:"

变量--空接口--relect.Value之间的转换关系:

int变量与反射变量之间的转换:

package main

import (
"fmt"
"reflect"
) func reflectTest(b interface{}) {
rTyp := reflect.TypeOf(b)
fmt.Printf("rTyp=%v,type=%T\n", rTyp, rTyp)
rVal := reflect.ValueOf(b)
fmt.Printf("rVal=%v,type=%T\n", rVal, rVal) iVal := rVal.Interface()
num2 := iVal.(int)
fmt.Printf("num2=%v,type=%T\n", num2, num2)
} func main() {
var num int =
reflectTest(num)
}

 结构体变量与反射变量之间的转换:

type student struct {
name string
age int
} func reflectTest02(b interface{}) {
rTyp := reflect.TypeOf(b)
fmt.Printf("rTyp=%v,type=%T\n", rTyp, rTyp)
rVal := reflect.ValueOf(b)
fmt.Printf("rVal=%v,type=%T\n", rVal, rVal) iVal := rVal.Interface()
stu2 := iVal.(student)
fmt.Printf("stu2=%v,type=%T\n", stu2, stu2)
fmt.Printf("name:%v,age:%v", stu2.name, stu2.age)
} func main() {
stu := student{
name: "tom",
age: ,
}
reflectTest02(stu)
}

反射注意事项和使用细节:
(1)reflect.Vale.Kind,获取变量的类别,返回的是一个常量;

(2)Type是类型,Kind是类别,Type和Kind可能是相同的,也可能是不同的;

比如:var num int=10的type是Int,Kind也是int

     var stu Student, stu的rype是pkg1.Student,Kind是struct

(3)通过反射介意让变量在interface{}和reflect.Value之间相互转换;

(4)使用反射的方式来获取变量的值,要求数据类型匹配;

(5)通过反射来修改变量,注意当使用SetXxx方法来设置需要通过对指针类型来完成,这样才能改变传入变量的值,同时需要使用到reflect.Value.Elem()方法;即rVal.Elem().SetInt(20)

具体实践;

使用反射来遍历结构体的字段,并调用结构体的方法,并获取结构体标签的值。

package main

import (
"fmt"
"reflect"
) type monster struct {
Name string `json:"name"`
Age int `json:"monster_age"`
Score float32
Sex string
} func (m monster) Print() {
fmt.Println("----strat----")
fmt.Println()
fmt.Println("----end----")
} func (m monster) GetSum(n1, n2 int) int {
return n1 + n2
} func (m monster) Set(name string, age int, score float32, sex string) {
m.Name = name
m.Age = age
m.Score = score
m.Sex = sex
} func testStruct(b interface{}) {
//获得类型
rtyp := reflect.TypeOf(b)
//获得值
rval := reflect.ValueOf(b)
//获得类别
kd := rval.Kind()
//如果kd不是指针类型且rval.Elem()不是结构体类别
if kd != reflect.Ptr && rval.Elem().Kind() == reflect.Struct {
fmt.Println("expect struct")
return
}
//获取结构体有几个字段
num := rval.Elem().NumField()
fmt.Printf("struct has %d fields\n", num)
//遍历每个字段
for i := ; i < num; i++ {
//输出该字段的值
fmt.Printf("field %d:值为=%v\n", i, rval.Elem().Field(i))
//获取该字段的json标签
tagval := rtyp.Elem().Field(i).Tag.Get("json")
//如果标签不为空,则打印出标签
if tagval != "" {
fmt.Printf("field %d:tag为=%v\n", i, tagval)
}
}
rval.Elem().Field().SetString("孙悟空")
//获取结构体有几个方法
numOfMethod := rval.Elem().NumMethod()
fmt.Printf("struct has %d methods\n", numOfMethod)
//获取第二个方法,函数的顺序是按首字母的ACSII进行排序的,所以这里第二个方法是Print
rval.Elem().Method().Call(nil)
//定义一个reflect.Value切片
var params []reflect.Value
//添加两个整型
params = append(params, reflect.ValueOf())
params = append(params, reflect.ValueOf())
//调用第一个方法,并传入参数(注意参数类型是reflect.Value切片)
res := rval.Elem().Method().Call(params)
//注意res是一个切片,里面只有一个值
fmt.Println("res=", res[].Int()) } func main() {
var a monster = monster{
Name: "tom",
Age: ,
Score: 20.9,
}
testStruct(&a)
fmt.Println(a)
}

要在反射中修改结构体的字段的值,必须传入的是地址,并且在反射中使用.Elem().SetXxx()

具体实践2:通过反射完成适配器

func main() {
test1 := func(v1 int, v2 int) {
fmt.Printf("v1=%d,v2=%d\n", v1, v2)
}
test2 := func(v1 int, v2 int, s string) {
fmt.Printf("v1=%d,v2=%d,s=%s", v1, v2, s)
}
bridge := func(call interface{}, args ...interface{}) {
//获取参数长度
n := len(args)
//定义参数切片
params := make([]reflect.Value, n)
//将参数存入到切片中
for i := ; i < n; i++ {
params[i] = reflect.ValueOf(args[i])
}
// for i := 0; i < n; i++ {
// fmt.Println(args[i])
// }
//获取函数名
function := reflect.ValueOf(call)
//将参数传给函数,并调用函数
function.Call(params)
} bridge(test1, , )
bridge(test2, , , "test2") }

运行结果:

具体实践3:通过反射操作任意结构体类型

type user struct {
UserID string
Name string
} func testReflectStruct() {
var (
model *user
sv reflect.Value
)
model = &user{}
sv = reflect.ValueOf(model)
//这里是指针类别
fmt.Println(sv.Kind().String())
sv = sv.Elem()
//这里是结构体类别
fmt.Println(sv.Kind().String())
sv.FieldByName("UserID").SetString("")
sv.FieldByName("Name").SetString("tom")
fmt.Println(model)
}

最新文章

  1. BigDecimal 详细解析
  2. Android学习——windows下搭建NDK_r9环境
  3. MyEclipse 中文乱码 史诗级解决方法。也可用于其他编码
  4. [Python笔记]第十六篇:web框架之Tornado
  5. Unity使用Mono.Xml代替System.Xml 测试
  6. WebVR认识
  7. 【WPF开发备忘】使用MVVM模式开发中列表控件内的按钮事件无法触发解决方法
  8. [Abp 源码分析]十六、后台作业与后台工作者
  9. Concept Drift(概念漂移)
  10. win 10 升级远程连接服务器 要求的函数不受支持
  11. juqery 点击张三触发李四的方法 trigger(); 和 被选元素前插入指定的内容的方法 brfore();
  12. css动画 aniamtion &amp; @keyframes
  13. sql语句最后一行显示统计。
  14. Android开发 ---基本UI组件3:单选按钮、多选按钮、下拉列表、提交按钮、重置按钮、取消按钮
  15. Linux巩固记录(4) 运行hadoop 2.7.4自带demo程序验证环境
  16. 汇编 MOVSX与MOVZX 指令
  17. 【iOS XMPP】使用XMPPFramewok(四):收发消息
  18. 蛮力法解决0_1背包问题新思路-——利用C语言位域类型
  19. 设置Linux SSH登录后的欢迎信息
  20. [log]利用logrotate对Linux log进行管理

热门文章

  1. Ubuntu 14.04 sudo免密码的方法| sudo不需要密码
  2. Process类调用exe,返回值以及参数空格问题
  3. SpringCloud之异常报警通知(八)
  4. R语言:绘制知识图谱
  5. app消息推送
  6. API 接口开发规范
  7. 转:linux环境mysql root用户密码重置
  8. 学习笔记64_k邻近算法
  9. Spring-Mybatis-SpringMVC三大框架整合
  10. 003.Kubernetes二进制部署准备