[go]反射
一、reflect.typeof()
如果传入的是一个接口,如果是动态绑定了一个实现结构体的,则显示具体结构体的type,否则是接口的名字。这个方法返回的是一个type接口,其实就是返回了 绑定类型的rtype,这个指针在value这个结构体有
a:=a{} a.age=19 a.name="pb" i:=1 log.println(reflect.typeof(a).name()) //类型的名字 a log.println(reflect.typeof(i).name()) //int //底层基础类型 log.println(reflect.typeof(a).kind(),reflect.typeof(i).kind()) //struct int log.println(reflect.typeof(a).kind().string()=="struct") //true //返回的是kind类型 需要通过string转化 否则是一个uint类型
typeof返回的是一个type接口下面看看type接口有哪些实现
type student struct { name string `pb:"名字"` age int `json:"年龄"` } type part1 struct { a bool b int32 //4 byte c int8 d int64 e byte } type part2 struct { e byte c int8 a bool b int32 d int64 }
利用反射可以查看结构体或其他类型的内存分配情况,如内存大小,字节对齐的大小等....
size():关于内存
为什么要字节对齐?
加快访问速度,减少读取次数。如果不对齐,那么一个数据的地址可能会分散到用两个字节,那么cpu就可能需要分两次读取。
我们假设cpu以4字节为单位读取内存。
如果变量在内存中的布局按4字节对齐,那么读取a变量只需要读取一次内存,即word1;读取b变量也只需要读取一次内存,即word2。
而如果变量不做内存对齐,那么读取a变量也只需要读取一次内存,即word1;但是读取b变量时,由于b变量跨越了2个word,所以需要读取两次内存,分别读取word1和word2的值,然后将word1偏移取后3个字节,word2偏移取前1个字节,最后将它们做或操作,拼接得到b变量的值。
显然,内存对齐在某些情况下可以减少读取内存的次数以及一些运算,性能更高。
另外,由于内存对齐保证了读取b变量是单次操作,在多核环境下,原子性更容易保证。
但是内存对齐提升性能的同时,也需要付出相应的代价。由于变量与变量之间增加了填充,并没有存储真实有效的数据,所以占用的内存会更大。这也是一个典型的空间换时间的应用场景。
- 增加cpu吞吐量,减少读取次数
- 保证原子操作
- 空间换时间,如果没有安排好内存的话,中间会多出很多空白
part1
part2
func main(){ s1 := student{"pb", 12} type_s1 := reflect.typeof(s1) type_part1 := reflect.typeof(part1{}) type_part2 := reflect.typeof(part2{}) //关于内存 log.println(type_s1.align(), type_part1.align()) //8 8 log.println(type_s1.fieldalign(), type_part1.fieldalign()) //8 8 log.println(type_part1.size(), type_part2.size()) //32 16 why?上图 }
key() elem()
type mymap map[int]string log.println(reflect.typeof(mymap{}).key()) //返回map类型 key的类型 int log.println(reflect.typeof(mymap{}).elem()) //返回 容器类型中元素的类型 string //it panics if the type's kind is not array, chan, map, ptr, or slice.
method() methodbyname()
反射方法。第一个传入0 1 2来表示方法 后面那个传入字符串
fieldbyxxxx()
反射属性,tag属性可以获得属性后面的注解调用get方法
二、reflect.valueof()
这是一个结构体,可以操作对象的值,每个方法都返回value来达到链式调用的目的,
type能实现的功能value都可以
type value struct { typ *rtype //typeof返回的东西 继承了type接口 保存了一个数据的类型和底层指针 ptr unsafe.pointer flag } type rtype struct { size uintptr ptrdata uintptr // number of bytes in the type that can contain pointers hash uint32 // hash of type; avoids computation in hash tables tflag tflag // extra type information flags align uint8 // alignment of variable with this type fieldalign uint8 // alignment of struct field with this type kind uint8 // enumeration for c alg *typealg // algorithm table gcdata *byte // garbage collection data str nameoff // string form ptrtothis typeoff // type for pointer to this type, may be zero }
method()
type stu struct { name string "名字" age int "年龄" } func (s *stu) say() { fmt.println(s.name) } func (s stu) hello() { fmt.println(s.name) } func (s stu) hello2(ss string,i int) { fmt.println(ss,i) }
s := stu{"pb", 12} v := reflect.valueof(s) fmt.println(v,v.field(0)) fmt.println(v.kind(), v.type().name()) fmt.println(v.fieldbyname("name"), v.field(0)) //操作方法 方法位置按照函数名字进行字典序排序 v.method(0).call(nil) //#调用无参函数 v.method(1).call([]reflect.value{reflect.valueof("ok"), reflect.valueof(1)}) //#调用有参函数 必须是value类型
elem()
要修改对象的值,必须指针的value调用elem方法才可以修改
只能指针的value(包括动态绑定的接口,如果这个接口的值是指针类型也可)才可以调用并且修改原来对象的值
s = stu{name:"biningo",age:18} sv:=reflect.valueof(s) log.println(sv.field(0)) pv:=reflect.valueof(&s) //// it panics if v's kind is not interface or ptr. //log.println(reflect.valueof(s).elem().canset()) log.println(pv.elem().field(0),pv.elem().field(0).canset()) //biningo true pv.elem().field(0).setstring("biningo") log.println(pv.elem().field(1).canset()) //false 必须要大写的字段才可以设置 log.println(s) //biningo 18 //对于没有接口的类型来说 返回的就是一个指针 i:=pv.interface() //返回空接口 //valueof返回的是实际动态绑定的类型 这里是*stu log.println(reflect.valueof(i).elem().canset()) //true 如果不加elem则false
三、value和type相互转换
type和value可以相互转化
通过type来创建一个value
t:=sv.type() //value->type log.println(t.name()) //stu //type创建value s2:=reflect.new(t) log.println(s2.type(),s2.elem().canset(),s2) //true因为返回的是*stu 都是默认值 s2.elem().field(0).setstring("biningo2") //s2.elem().field(1).setint(19) 私有字段不可设置 log.println(s2)
value可以直接转化为type
调用value的type方法即可
value转化为具体对象
value-->interface-->obj
//value转化为具体对象 //value-->interface-->obj inter:=sv.interface() //*stu s1:=inter.(stu) log.println(s1) // biningo 18