Go 反射包使用教程

引子

几乎所有高级语言都有反射功能,以用于语言的灵活性,实现各种封装。

Java(java.lang.reflect):

1//获得Person的Class对象 2Class<?> cls = testJavaSE.Person.class;//Class.forName("testJavaSE.Person"); 3//创建Person实例 4Person p = (Person)cls.newInstance(); 5//获得Person的Method对象,参数为方法名,参数列表的类型Class对象 6Method method = cls.getMethod("eat",String.class); 7//invoke方法,参数为Person实例对象,和想要调用的方法参数 8String value = (String)method.invoke(p,"肉"); 9//输出invoke方法的返回值 10System.out.println(value);

Php(Reflection)

1$reflect = new \\ReflectionClass(); 2if($reflect->hasMethod("eat")) { 3 echo $reflect->getMethod("eat")->invoke($reflect->newInstance(), "php"); 4}

可以看到,我们可以很容易实现灵活的功能。那么go作为一门语法约束较为严格的语言,如果不支持反射的话,真的会很难大规模普及,所以官方还是提供了一个灵活的反射包(ps: 虽然不太好用)

go 反射包

go反射包是存在与内核里面的

GOROOT/src/reflect/*

这里要说明一点,go不是一门纯正的面向对象语言,所以反射包的涉及也略有不同。

反射由reflect包提供支持,主要方法:

  • func TypeOf ( i interface{} ) Type:

如 reflect.Typeof(x) ,形参x被保存为一个接口值并作为参数传递(复制),方法内部会把该接口值拆包恢复出x的类型信息保存为reflect.Type并返回

  • func ValueOf ( i interface{} ) Value:

如 reflect.ValueOf(x) ,形参被保存为一个接口值并作为参数传递(复制), 方法内部把该接口值的值恢复出来保存为reflect.Value并返回;

type

Type 接口:可以表示一个Go类型

Kind()将返回一个常量,表示具体类型的底层类型

Elem()方法返回指针、数组、切片、map、通道的基类型;

可用反射提取struct tag,还能自动分解,常用于ORM映射、数据验证等;

辅助判断方法Implements()、ConvertibleTo()、AssignableTo()

example(判断一个结构体是否包含某个属性):

1t := reflect.TypeOf(s) 2if _, ok := t.FieldByName("Name"); ok { 3 return true 4} 5return false

value

Value 结构体:可以持有一个任意类型的值

1调用 ValueType() 将返回具体类型所对应的 reflect.Type(静态类型) 2调用 ValueKind() 将返回一个常量,表示具体类型的底层类型 3Interface方法是ValueOf方法的逆,它把一个reflect.Value恢复成一个接口值,把Value中保存的类型和值的信息打包成一个接口表示并返回: 4通道类型的反射对象:有TrySend()、TryRecv()方法 5IsNil()方法判断反射对象保存的值是否为nil

example(反射一个普通的数值):

1var x int64 = 0 2func getInterfaceValueInt64(x interface{}) int64 { 3 //这里基础类型已经实现了封装 4 //i64 := reflect.ValueOf(x).Int() 5 i64 := reflect.ValueOf(x).(int64) 6} 7d: =getInterfaceValueInt64(x) 8fmt.Println(d)

那么复杂类型如何处理呢?继续代码举例吧:

example(array or slice):

1func SliceBuildWithInterface(v interface{}) reflect.Value { 2 typ := reflect.TypeOf(v) // 获取类型 3 sliceValue := reflect.MakeSlice(reflect.SliceOf(typ), 0, 0)//生成value对象 4 5 slice := reflect.New(sliceValue.Type()) //构建切片 6 slice.Elem().Set(sliceValue) //设置切片值 7 8 return slice 9}

为什么需要反射呢?

  • 功能更强大
  • 更安全,防止直接调用没有暴露的内部方法
  • 可维护,直接写字符串是硬编码
点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )

Go 反射包使用教程 - HelloWorld