首页 > 其他分享 >Go | 一分钟掌握Go | 10 - 反射

Go | 一分钟掌握Go | 10 - 反射

时间:2023-05-03 22:32:19浏览次数:50  
标签:10 函数 反射 fmt 一分钟 reflect 得到 Go

 作者:Mars酱

 声明:本文章由Mars酱编写,部分内容来源于网络,如有疑问请联系本人。

 转载:欢迎转载,转载前先请联系我!

前言

反射你以为只在Java中有吗?Go也有反射机制,很多的标准库中,也使用了反射机制,比如fmt包中的encoding包,都是依赖反射机制的。Go的反射比Java的更简单,就只依赖两两个对象:一个Type,一个Value,前者是得到定义对象的类型,比如定义int类型的变量a,反射之后得到int这个类型;后者是得到该变量的值,如果a没有赋值,那么反射得到的a的值就是0。

怎样反射得到对象的类型?

我们可以通过reflect的TypeOf()函数可以获得任意值的类型Type对象,我们试试:

import (
	"fmt"
	"reflect"
	"testing"
)

// author: mars酱
func Test_reflect2(t *testing.T) {
	var pi float32 = 3.1415926
	reflectType1(pi)
}

func reflectType1(x interface{}) {
    // 调用TypeOf函数
	typeName := reflect.TypeOf(x)
	fmt.Printf("类型为:%s\n", typeName.Name())
}

我创建了一个函数reflectType1,函数内部调用TypeOf得到reflect.Type对象(看下面浮动窗的提示信息)

Go | 一分钟掌握Go | 10 - 反射_Go

得到Type对象之后,再调用.Name()函数得到类型的名字,运行一下,得到结果:

Go | 一分钟掌握Go | 10 - 反射_反射_02

我们得到了pi的类型是float32,是不是比java简单多了

怎样反射得到对象的值?

得到了类型对象,那么我们来反射获取一下对象的值。Go中通过反射获取值的方法是通过reflect的ValueOf()函数获取的。我们试试看:

import (
	"fmt"
	"reflect"
	"testing"
)

// author: mars酱
func Test_reflect2(t *testing.T) {
	var pi float32 = 3.1415926
	reflectType1(pi)

	reflectValue1(pi)

}

func reflectType1(x interface{}) {
	typeOf := reflect.TypeOf(x)
	fmt.Printf("类型为:%s\n", typeOf)
}

func reflectValue1(x interface{}) {
	valueOf := reflect.ValueOf(x)
	fmt.Printf("值为:%v\n", valueOf)
}

运行一下,得到结果:

Go | 一分钟掌握Go | 10 - 反射_Go_03

相比java,是不是显得go真的太容易和简单很多啊

怎样反射得到对象结构体?

通常,我们并不是只有基本类型的对象的,我们庞大的业务系统是由很多自定义的结构体对象组成的,这里我们看怎么反射自定的结构体。先自定义一个结构体,然后赋值:

type person struct {
	name string
	age  int
}

man := person{age: 98, name: "mars酱"}

再定义一个函数,用来反射结构体:

func reflectStruct1(x interface{}) {
	// 1. 得到Type
	typeOf := reflect.TypeOf(x)
    // 2. 得到Value
	valueOf := reflect.ValueOf(x)

	// 3. 得到Type下的参数数量
	numField := typeOf.NumField()
	for i := 0; i < numField; i++ {
		// 得到StructField对象
		field := typeOf.Field(i)
		value := valueOf.Field(i)
		fmt.Printf("变量名:%s 索引下标:%d 类型:%v 值:%v \n", field.Name, field.Index, field.Type, value)
	}
}

运行之后,打印结果如下:

Go | 一分钟掌握Go | 10 - 反射_Go_04

这样,就得到了结构体中属性的类型还有值,还得到了属性是下标顺序,name是第一个,下标索引为0,age是第二个,下标索引是1

反射调用函数吧

在java中,我们经常使用反射调用,知道一个对象的类型,去反射得到里面的函数,然后给函数传入参数之后,再调用反射出来的函数,这在java的框架中是家常便饭了,那么这次我们看看Go里面怎么做的。

先定义一个函数,一个简单的函数,我们让这个函数做个加法计算:

func addFunc1(a, b int) int {
	return a + b
}

然后创建一个反射这个函数的函数(稍微有点绕口):

// 反射addFunc1函数的函数
func reflectFunc(x interface{}, a, b int) {
	// 1. 先反射值对象
	funcValue := reflect.ValueOf(x)
	// 2. 传入两个参数给构造函数
	paramList := []reflect.Value{reflect.ValueOf(a), reflect.ValueOf(b)}
	// 3. 反射调用函数
	retList := funcValue.Call(paramList)
	// 4. 获取结果
	fmt.Printf("反射调用得到的结果:%v\n", retList[0].Int())
}

这个反射函数需要传入三个参数:一个x对象,两个需要做加法的变量a和b。最后我们在单元测试函数中去调用:

// 调用反射函数的函数
reflectFunc(addFunc1, 10, 20)

运行一下,得到结果如下:

Go | 一分钟掌握Go | 10 - 反射_反射_05

小结一下

Go的反射相比Java的更简单容易理解,但是有几个点需要知道:

  1. 反射数组、切片、Map、指针等类型的变量,它们调用.Name()函数,得到的都是空;
  2. 反射中的类型如果错误会在真正运行的时候才会引发panic,那很可能是在代码写完的很长时间之后
  3. 使用太多反射的代码会很难阅读和难以理解;
  4. 网传Go的反射的性能低下,而且基于反射实现的代码通常比正常代码运行速度慢一到两个数量级;

所以,斟酌而行。也希望未来Go的性能会更高,毕竟最新版才1.20.*版本呢~

标签:10,函数,反射,fmt,一分钟,reflect,得到,Go
From: https://blog.51cto.com/marsz/6241576

相关文章

  • 记忆化搜索 P1028 数的计算
    P1028[NOIP2001普及组]数的计算-洛谷|计算机科学教育新生态(luogu.com.cn)一开始是想暴力搜索的,也就是枚举比n/2小的数,但是只过了5个点,其他点都TLE然后就开始想有没有优化方法以6为例子6/2=3,那么以6为首的长度为2的序列就有61,62,63,也就是所有小于等于3的数的个数接下......
  • 力扣---1003. 检查替换后的词是否有效
    给你一个字符串s,请你判断它是否有效。字符串s有效需要满足:假设开始有一个空字符串t="",你可以执行任意次下述操作将t转换为s:将字符串"abc"插入到t中的任意位置。形式上,t变为tleft+"abc"+tright,其中t==tleft+tright。注意,tleft和tright可能为......
  • 2022 杭电多校 第十场 1001 Winner Prediction(最大流)
    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=7244杭电题解:先让1号选手赢下所有和他有关的比赛,设此时选手赢了a场比赛。如果存在某个ai>a1则1号选手不可能成为冠军。否则选手至多还能再赢bi=a1-ai场比赛。考虑建立一张网络流图:每场未进行的比赛在图中用一个点......
  • NC51101 Lost Cows
    题目链接题目题目描述\(N(2\leqN\leq8,000)\)cowshaveuniquebrandsintherange1..N.Inaspectaculardisplayofpoorjudgment,theyvisitedtheneighborhood'wateringhole'anddrankafewtoomanybeersbeforedinner.Whenitwastimetoli......
  • KIT107 编程内容
    1/9KIT107Programming2023Assignment2DueDateTheassignmentisdueat11:55PMWednesdayMay3rd2023.Itisworth24%ofyourmarkandyoushouldcompleteitasanindividual.BackgroundUScitizensloveguns.UScitizenstrytobuyguns.Lotsofguns.Lots......
  • Leetcode1~10题整理
    1.两数之和哈希表:O(n)classSolution{public:vector<int>twoSum(vector<int>&nums,inttarget){unordered_map<int,int>hs;intn=nums.size();for(inti=0;i<n;i++){intx=target-n......
  • 「解题报告」ARC103D Distance Sums
    给Kaguya看了一眼,Kaguya用了一分钟切了。我看了一个小时。这就是神吗。考虑一个点往叶子走答案的贡献,显然距离和会变化\(-siz_u+(n-siz_u)=n-2siz_u\)。如果我们以重心为根,那么所有的\(n-2siz_u>0\),那么这实际上是一个小根堆。那么我们考虑从大往小枚举叶子,然......
  • django 请求与响应
    请求与响应转递数据与接收三个请求方式 三个响应方式 defreq_list(request):#请求1#print(request.method)#m1=request.method#请求2#print(request.GET)#m2=request.GET#请求3#print(request.POST)#m3=......
  • django.core.exceptions.ImproperlyConfigured: mysqlclient 1.4.3 or newer is requi
     1、在项目中__init__.py中这个报错原因,python3.5以上版本不支持这种方式frompymysqlimportinstall_as_MySQLdbinstall_as_MySQLdb()解决:importpymysqlpymysql.version_info=(1,4,3,"final",0)#指定了pymysql的版本:1.4.3,按照你版本修改pymysql.install_as_MySQLdb()......
  • 《SQLi-Labs》02. Less 6~10
    目录Less-6知识点题解Less-7题解Less-8题解Less-9知识点题解Less-10题解sqli。开启新坑。Less-6知识点布尔盲注。与Less-5基本相同。这里只简略写大致步骤。length()函数:返回字符串所占的字节数。ascii()函数:返回字符串最左字符的ASCII值。如果是空字符串,返回0。如......