go reflection

1. 接口描述

一个接口变量类型里面存储一个键值对: 赋给接口变量的具体值,该值对应的类型描述。
举个例子:

var r io.Reader
tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
if err != nil {
    return nil, err
}
r = tty

r 包含的键值对(value, type)为(tty, *os.File), 其中类型*os.File不仅包含Read方法,还包含所有它自己实现的方法。tty包含值本身和类型相关的所有信息。

2. 反射

a. reflect.Value类型包含有Type方法,可以获取它的type类型。
b. reflect.Value和relfect.Type都有Kind方法,返回存储的具体底部类型。
c. 可以通过调用set方法,设置反射后实例的值,但是被反射的实例必须是引用类型,因为按值拷贝的变量反射后改变的是本身的值, 而这样操作并没有任何意义。为避免这种无意义的操作,调用这种操作会导致程序panic。
对于c的补充示例

var x float64 = 3.4
v := reflect.ValueOf(x)
v.SetFloat(7.1) // Error: will panic.
panic: reflect.Value.SetFloat using unaddressable value

反射实例v 不能被赋值, 可以通过以下方法进行判断

var x float64 = 3.4
v := reflect.ValueOf(x)
fmt.Println("settability of v:", v.CanSet())
//settability of v: false

反射对象是否能进行改值操作,取决于反射对象是否持有原有的对象,而不是原有对象的一份拷贝。如下:

var x float64 = 3.4
p := reflect.ValueOf(&x) // Note: take the address of x.
fmt.Println("type of p:", p.Type())
fmt.Println("settability of p:", p.CanSet())

对于struct类型的操作

type T struct {
    A int
    B string
}
t := T{23, "skidoo"}
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()) //注意此处通过reflect.Type来获取字段的名字。
}

由于s中持有的是类型的引用,我们可以直接对s的字段进行赋值

s.Field(0).SetInt(77)
s.Field(1).SetString("Sunset Strip")
fmt.Println("t is now", t)

d. 可以通过调用reflect.Value的interface方法进行拆包操作,获取反射对应的实例(interface类型)

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,026评论 19 139
  • 第一次知道反射的时候还是许多年前在学校里玩 C# 的时候。那时总是弄不清楚这个复杂的玩意能有什么实际用途……然后发...
    勿以浮沙筑高台阅读 1,145评论 0 9
  • 大学四年,现剩下100天。回过头看这些年,如果没有考研折腾一下,我可能很难搞明白我到底学到了什么知识。 大一和大二...
    远方的女儿阅读 1,114评论 0 6
  • 2016.9.8夜,遇见。
    隐娘曰阅读 166评论 0 0
  • 文/吴以辉 对于大部分没来得及看懂比特币的场外者来说,比特币只是一小撮人击鼓传花的游戏,是另外一场郁金香泡沫。连以...
    吴以辉2000阅读 467评论 0 0