Golang反射的使用的正确姿势
Go本身不支持模板
,因此在以往需要使用模板的场景下往往就需要使用反射(reflect)
. 反射使用多了以后会容易上瘾,有些人甚至会形成一种莫名其妙的鄙视链。文人相轻,看来在需要动手指的领域历来如此:) 。反射有两个问题,在使用前需要三思:
大量
的使用反射会损失一定性能Clear is better than clever. Reflection is never clear.
Go的类型设计上有一些基本原则,理解这些基本原则会有助于你理解反射的本质:
- 变量包括
<type, value>
两部分。理解这一点你就知道为什么nil != nil
了。 type
包括static type
和concrete type
. 简单来说static type
是你在编码是看见的类型,concrete type
是runtime系统看见的类型。- 类型断言能否成功,取决于变量的
concrete type
,而不是static type
. 因此,一个reader
变量如果它的concrete type
也实现了write
方法的话,它也可以被类型断言为writer
. - Go中的反射依靠
interface{}
作为桥梁,因此遵循原则3. 例如,反射包.Kind
方法返回的是concrete type
, 而不是static type
.
Talk is cheap, show some code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
package main import ( "fmt" "reflect" ) type T struct { A int B string } func main() { t := T{23, "skidoo"} tt := reflect.TypeOf(t) fmt.Printf("t type:%v\n", tt) ttp := reflect.TypeOf(&t) fmt.Printf("t type:%v\n", ttp) // 要设置t的值,需要传入t的地址,而不是t的拷贝。 // reflect.ValueOf(&t)只是一个地址的值,不是settable, 通过.Elem()解引用获取t本身的reflect.Value s := reflect.ValueOf(&t).Elem() typeOfT := s.Type() for i := 0; i < s.NumField(); i++ { f := s.Field(i) fmt.Printf("%d: %s %s = %v\n", i, typeOfT.Field(i).Name, f.Type(), f.Interface()) } } // 输出结果 // t type:main.T // t type:*main.T // 0: A int = 23 // 1: B string = skidoo |
–EOF–
版权声明
转载请注明出处,本文原始链接
转载请注明出处,本文原始链接