golangreflect的简单介绍
本篇文章给大家谈谈golangreflect,以及对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。
本文目录一览:
- 1、go语言的reflect(反射)
- 2、Golang高效地拷贝big.Int
- 3、golang reflect.value.FieldByIndex() panic?
- 4、golang reflect反射(一):interface接口的入门(大白话)
- 5、如何利用golang 反射值来定义一个变量
- 6、这可能是最全的golang的"=="比较规则了吧
go语言的reflect(反射)
1、反射可以在运行时州此 动态获取变量的各种信息 ,比如变量的类型、类别;
2、如果是结构体变量,还可以获取到结构体本身的信息(包括结构体的字段、方法);
3、通过反射,可以修改 变量的值 ,可以调用关联的方法;
4、使用反射,需要import " reflect ".
5、示意图:
1、不知道接口调用哪个函数,根据传入参数在运行时确定调用的具体接口,这种需要对函数或方法反射。
例如以下这种桥接模式:
示例第一个参数funcPtr以接口的形式传入函数指针,函数参胡消数args以可变参数的形式传入,bridge函数中可以用反射来动态执行funcPtr函数。
1、reflect.TypeOf(变量名),获取变量的类型,返回reflect.Type类型。
2、reflect.ValueOf(变量名),获取变量的值,返回reflect.Value类型reflect.Value是一个结构体类型。
3、变量、interface{}和reflect.Value是可以互相转换的,这点在实际开发中,会经常使用到。
1、reflect.Value.Kind,获取变量的 类别(Kind) ,返回的是一个 常量 。在go语言文档中:
示例如下所示:
输出如下:
Kind的范畴要比Type大。比如有Student和Consumer两个结构体,他们的 Type 分别是 Student 和 Consumer ,但是它们的 Kind 都是 struct 。
2、Type是类型,Kind是类别,Type和Kind可能是相同的,也可能是不同的。
3、通过反射可以在让 变量 在 interface{} 和 Reflect.Value 之间相互转换,这点在前面画过示意图。
4、使用反射的方式来获取变量的值(并返回对应的类型),要求数据类型匹配,比如x是int,那么久应该使用reflect.Value(x).Int(),而不能使用其它的,否则报panic。
如果是裤迹知x是float类型的话,也是要用reflect.Value(x).Float()。但是如果是struct类型的话,由于type并不确定,所以没有相应的方法,只能 断言。
5、通过反射的来修改变量,注意当使用SetXxx方法来设置需要通过对应的指针类型来完成,这样才能改变传入的变量的值,同时需要使用到reflect.Value.Elem()方法。
输出num=20,即成功使用反射来修改传进来变量的值。
6、reflect.Value.Elem()应该如何理解?
[img]Golang高效地拷贝big.Int
试图通过拷贝 *big.Int 指针所指的结构:
这种方式是源隐错误的,因饥铅为 big.Int 结构内部有 slice ,拷贝结构的话内部的 slice 仍然是共享内存。
点击运行测试
思想:
思想:
copier 内部实现使用了 reflect 。
思想
Benchmark测试
big.Int = 10
big.Int = 100000000222222222222222222220000000000000000000
比较两次运行的结果,发现:
+ 0 是最好的选择烂裂好
golang reflect.value.FieldByIndex() panic?
我测试了芹燃一下
{0}可以得到fieldVals: zhangsan
{1}可以宏首衡得蔽做到fieldVals: 33
但不能是{0, 1}
golang reflect反射(一):interface接口的入门(大白话)
这是它的优点,因为编译器在编译时不去确定你传的到底是什么类型,你传一个string,它能接收,你传一个对象struct,它也能接收,它只有一个要求,实现我要求实现的方法!
既然interface是不限定类型,是通用类型,这是一种开放表现,这种开放怎么实现的呢?方差敬法就是不去检验你的类型,既然不检验那也不去记录你的类型!!!!注意interface不记录你的类型,所以不管你是string,struct,int,我都不管,我都不记录,我只记录你的地址,结果是编译器在编译时也不知道你是什么类型,你有什么字段!
但是现在有一个问题,编译器也没办法确定一个interface以前是什么类型!(编译时)这就是因果关系:为了达到通用,interface不做确定工作,结果就是interface也不知道以前的类型。
一个类型转接口的过程,就是放弃自我类型的过程,变成了没有类型。
这样做有什么好处呢,很显然是:通用,如果把一个函数的传入参数设置为空接口(interface{}),那么任何类型当做参数都能够调用该接口,最好的例子就是:
它就是一个很标准的例子,println传入参数可以是任何类型,都能打印出它的值。
当然你可以说你记得,因为是你把它转换成interface,你理所当然的记得,可编译器不知道啊,interface不包含类型,也就是说你没有让它去记录,所以它不知道。
针对这个问题,go语言给了一个解决方案,断言,当将一个interface转换成它原来类型的时候,在它后面指明它的原来类型,这样编译器就知道该按照什么类型去解析了。(其实说白了,这就是通过人的记忆,编译器不知道是什么类型,你告诉编译器就可以了)
断言其实是先获取interface的动态类型,然后与你指定的类型做判断,如果一致,将它转换成你指定的类型。如果不知道动态类型,可以看这篇文章:
从报错可以看出, 不能直接转换,需要对接口先进行断言
通常情况下,一个变量在确定类型的情况下编译器知道他有哪些功能(注意,这里是针对编译时),比如一个int类型,编译器在编译时知道能对他加减int,不能加减float,如果你这么做我就给你报错。一个struct包含哪些字段,不包含哪些字段,我定义一个user结构体,里面只有name和age两个字段,那么你只能取我这两字段的值,你如果取height,我就给你报错。
这些都是正常情况下的,但是对于一个接口呢,编译器会变成瞎子!在编译的时候它不知道你原来是什么类型,所以它也没法确定你包含什么字段,同样是之前那个user结构体,当把它转换成接口以后,编译器就对它的类型一无所知了,你获取name字段,这有接口有没有呢?编译器不知道!你请求height字段,这个泛型有没有呢?编译器仍然不知道。所以你编译时不能修改接口里的数据,既然编译时 不能修改,那就只能在运行时修改了。
这个时候就该反射登场了,它能够在运行时修改接口的数据,通过追根溯源,获取接口底层的实际数据和类型,让你能够对接口的源数据进行操作。
换一种大白话的说法,反射就是刨根凳庆友问底,获取这个接口究竟是怎么产生的,因为哪怕一个类型转变成接口时放弃了自己的枣槐类型,但是它的本质不会变的,就像赵本山的小品里所说:小样,别以为你脱掉马甲我就不认识你了!对,它的底层里仍然存储了它的数据类型,只是藏的比较深,一般手段拿不到,但我们仍然能够通过反射(这个包根问底的工具)来确定你究竟包含哪些字段和值,确定你究竟是蛇还是脱了马甲的乌龟!
如何利用golang 反射值来定义一个变量
之前写java的时候就已经知道了有反射这个概念,看过一遍文戚橡章专门介绍了一下java的反射机制,不过现在忘记了。
今天写一个通用函数的时候要对传入的参数经行类型判断,还要定义与其像同类型的变量经行取址运算,baidu, google,golang reflect包也看了好久,也没看到将返回值来定义个变量的办法。最后在一篇博客中旁滑得到灵感—–点击可以看看。
这篇文章中没有告诉怎么将反射值去定义一个变量,但看完之后思考一下,既然要返回一个类型,但是类型又是不确定的,若存在这样一个返回变量的函数,则其返回类型必是Interface,在官网文档里找返回类型是Interface的函数,就是它了,它是Value类型的一个函数,所以就不能使用reflect.TypeOf(i interface{})来运仔腊操作了,就只能用reflect.ValueOf().于是慢慢结合上诉博客加文档,get~
package main
import (
"reflect"
"fmt"
)
func main() {
v2 := "tangs"
fmt.Println("v2's value is : ", v2, ", type is : ", reflect.TypeOf(v2))
ty := reflect.ValueOf(v2).Elem()
s := ty.Interface()
s = "tangs"
fmt.Println("s's value is : ", s, ", type is : " ,reflect.TypeOf(s))
}
这可能是最全的golang的"=="比较规则了吧
大家经常用"=="来比较两个变伏伍量是否相等。但是golang中的"=="有很多细节的地方,跟php是不一样的。很多时候不能直接用"=="来比较,编译器会直接报错。
golang中基本类型的比较规则和复合类型的不一致,先介绍下golang的变量类型:
golang中的基本类型
比较的两个变量类型必须相等。而且,golang没有隐式类型转换,比较的两个变量必须类型完全一样,类型别名也不行。如果要比较,先做类型转换再比较。
复合类型是逐个字段,逐个元素比较的。需要注意的是, array 或者struct中每个元素必须要是可比较的,如果某个array的元素 or struct的成员不能比较(比如是后面介绍的slice,map等),则此复合类型也不能比较。
逐个成员比较类型和值。每个对应成员的比较遵循基本类型变量的比较规则。
但是如果struct中有不可比较的成员类型时:
可以看到,struct中有slice这种不可比较的成员时,整个struct都不能做比较,即使没有对slice那个成员赋值(slice默认值为nil)
slice和map的比较规则比较奇缺前或怪,我们先说普通的变量引用类型val和channel的比较规则。
引用类型变量存储的是某个变量的内存地址。所以引用类型变量的比较,判断的是这两个引用类型存储的是不是同一个变量。
上面看起来比较废话,但是得理解引用类型的含义。不然对判断规则还是不清楚。
slice类型不可比较,只能与零值nil做比较。
关于slice类型不可比较的原因,后面会专门写文章做讨论。
map类型和slice一样,不能比较,只能与nil做比较。
接口类型的变量,包含该接口变量存储的值和值的类型两部分组成,分别称为接口的动态类型和动态值。 只有动态类型和动态值都相同时,两个接口变量才相同:
而悔雀且接口的动态类型必须要是可比较的,如果不能比较(比如slice,map),则运行时会报panic。因为编译器在编译时无法获取接口的动态类型,所以编译能通过,但是运行时直接panic:
golang的func作为一等公民,也是一种类型,而且不可比较
上面说过,map和slice是不可比较类型,但是有没有特殊的方法来对slice和map做比较呢,有
reflect.DeepEqual函数可以用来比较两个任意类型的变量
对map类型做比较:
对slice类型做比较:
对struct类型做比较:
可以发现,只要变量的类型和值相同的话,reflect.DeepEqual比较的结果就为true
直接看用例:
结果为:
1, golang的类型再定义和类型别名
2,golang的slice和map为什么不可以比较
1,
2,
3,
关于golangreflect和的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。