反射基本介绍:

(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)
}

(四十五)golang--反射的更多相关文章

  1. NeHe OpenGL教程 第四十五课:顶点缓存

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  2. Gradle 1.12用户指南翻译——第四十五章. 应用程序插件

    本文由CSDN博客貌似掉线翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...

  3. SQL注入之Sqli-labs系列第四十一关(基于堆叠注入的盲注)和四十二关四十三关四十四关四十五关

    0x1普通测试方式 (1)输入and1=1和and1=2测试,返回错误,证明存在注入 (2)union select联合查询 (3)查询表名 (4)其他 payload: ,( ,( 0x2 堆叠注入 ...

  4. “全栈2019”Java第四十五章:super关键字

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  5. 孤荷凌寒自学python第四十五天Python初学基础基本结束的下阶段预安装准备

     孤荷凌寒自学python第四十五天Python初学基础基本结束的下阶段预安装准备 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 今天本来应当继续学习Python的数据库操作,但根据过去我自 ...

  6. (十四--十五)数据库查询优化Part I

    (十四--十五)数据库查询优化Part I 如果理解的有问题.欢迎大家指出.这也是我在看课记得笔记..可能会有很多问题 查询优化的重要性 请记住用户只会告诉DMBS他们想要什么样的结果,而不会告诉他们 ...

  7. 《手把手教你》系列技巧篇(四十五)-java+ selenium自动化测试-web页面定位toast-上篇(详解教程)

    1.简介 在使用appium写app自动化的时候介绍toast的相关元素的定位,在Web UI测试过程中,也经常遇到一些toast,那么这个toast我们这边如何进行测试呢?今天宏哥就分两篇介绍一下. ...

  8. 第四十五个知识点:描述一些对抗RSA侧信道攻击的基础防御方法

    第四十五个知识点:描述一些对抗RSA侧信道攻击的基础防御方法 原文地址:http://bristolcrypto.blogspot.com/2015/08/52-things-number-45-de ...

  9. abp(net core)+easyui+efcore实现仓储管理系统——入库管理之九(四十五)

    abp(net core)+easyui+efcore实现仓储管理系统目录 abp(net core)+easyui+efcore实现仓储管理系统——ABP总体介绍(一) abp(net core)+ ...

  10. Coding and Paper Letter(四十五)

    资源整理. 1 Coding: 1.Python库gempy,一种基于Python的开源三维结构地质建模软件,它允许从界面和方向数据隐式(即自动)创建复杂的地质模型. 它还支持随机建模以解决参数和模型 ...

随机推荐

  1. OTA升级详解(一)

    不积跬步,无以至千里: 不积小流,无以成江海. 出自荀子<劝学篇> 1.概念解释 OTA是何物? 英文解释为 Over The Air,既空中下载的意思,具体指远程无线方式,OTA 技术可 ...

  2. redis系列之------对象

    前言 Redis 并没有直接使用数据结构来实现键值对数据库, 而是基于这些数据结构创建了一个对象系统, 这个系统包含字符串对象.列表对象.哈希对象.集合对象和有序集合对象这五种类型的对象, 每种对象都 ...

  3. Java基础(二十八)Java IO(5)RandomAccessFile类与过滤器流(Filter Stream)

    一.RandomAccessFile类 使用RandomAccessFile类可以读取任意位置数据的文件. 1.构造方法 RandomAccessFile(String name, String mo ...

  4. django-Views之request(二)

    book/views.py def index(request): http_list = { '<h1>请求协议: <span style="color:red" ...

  5. 设计模式C++描述----10.装饰(Decorator)模式

    一. 举例 我之前做过一个文件系统就叫 MyFileSys 吧,后来的话,客户想加入一些附加功能,比如压缩.加密.杀毒之类的操作,这些附加操作没有先后顺序,比如你可以先压缩再加密,也可以先杀毒再压缩, ...

  6. SpringBoot 常用注解简单总结

    终于有时间对刚学的SpringBoot注解总结一下了,Annotation(注解)是JDK 5.0之后及以后版本引入的,这个时候需要在Spring中申明一个Bean,只能通过xml的方式,非常繁琐.但 ...

  7. Asp.net Core 系列之--1.事件驱动初探:简单事件总线实现(SimpleEventBus)

    ChuanGoing 2019-08-06  前言 开篇之前,简单说明下随笔原因.在园子里游荡了好久,期间也起过要写一些关于.NET的随笔,因各种原因未能付诸实现. 前段时间拜读daxnet的系列文章 ...

  8. (25)ASP.NET Core EF查询(复杂查询运算符、原生SQL查询、异步查询)

    1.复杂查询运算符 在生产场景中,我们经常用到LINQ运算符进行查询获取数据,现在我们就来了解下生产场景经常出现几种复杂查询运算符. 1.1联接(INNER JOIN) 借助LINQ Join运算符, ...

  9. 简单看看@RequestBody注解原理

    又到了很无聊的时候了,于是随便看看源码假装自己很努力的样子,哈哈哈: 记得上一篇博客随便说了一下RequestBody的用法以及注意的问题,这个注解作为非常常用的注解,也是时候了解一波其中的原理了. ...

  10. Python 基础 装饰器

    今天把学过的装饰器的知识进行回顾一下,说到装饰器,第一反应就是这个东西呢就是用来装逼的,为啥这样说呢,是应为没有这个东西照样可以干活,大部分工作都是可以做的,不管咋样还是把学过的装逼器梳理一下吧. 一 ...