美文网首页
深入理解Golang反射

深入理解Golang反射

作者: 昔召阆梦 | 来源:发表于2020-04-10 11:40 被阅读0次

反射

计算机中提到的反射一般是指,程序借助某种手段检查自己结构的一种能力,通常就是借助编程语言中定义的类型(types)。因此,反射是建立在类型系统上的。

go是静态类型化,每个变量都有一个静态类型,也就是说,在编译时,变量的类型就已经确定。不显示地去做强制类型转换,不同类型之间是无法相互赋值的。

有一种特殊的类型叫做接口(interface type),一个接口表示的是一组方法集合。一个接口变量能存储任何具体的值,只要这个值实现了这个接口的方法集合。比如io包中的Reader和Writer,io.Reader接口变量能够保存任意实现了Read方法的类型所定义的值。

一个特殊接口就是空接口interface{},任何值都可以说实现了空接口,因为空接口中没有定义方法,所以空接口可以保存任何值

一个接口类型变量存储了一对值:赋值给这个接口变量的具体值 + 这个值的类型描述符。更进一步的讲,这个“值”是实现了这个接口的底层具体数据项(underlying concrete data item),而这个“类型”是描述了具体数据项(item)的全类型(full type)。

所以反射是干嘛的呢?反射是一种检查存储在接口变量中的(类型,值)对的机制。reflect包中提供的2个类型Type和Value,提供了访问接口值的reflect.Type和reflect.Value部分。

三大法则

  1. Reflection goes from interface value to reflecton object:从interface{} 变量可以反射出反射对象;
type MyInt int32

func main() {
    var x MyInt = 7
    v := reflect.ValueOf(x)
    t := reflect.TypeOf(x)
    fmt.Println("type:", t)        // type: main.MyInt
    fmt.Println("value:", v)       // value: 7
    fmt.Println("kind:", v.Kind()) // kind: int32
    fmt.Println("type:", v.Type()) // type: main.MyInt
    x = MyInt(int32(v.Int))        // v.Int returns a int64
}

​ reflect.Value的Type返回的是静态类型MyInt,而kind()方法返回的是底层类型int32;为了保持API简单,value的Setter和Getter类型方法操作,是包含某个值的最大类型,v.Int()返回的是int64,必要时转化成实际类型。

  1. Reflection goes from reflection object to interface value:从反射对象可以获取 interface{} 变量;
type MyInt int32

func main() {
    var x MyInt = 7
    v := reflect.ValueOf(x)
    y := v.Interface().(int32)
    fmt.Println(y) // 7
}

对于一个reflect.Value,可以用Interface方法恢复成一个接口值,效果就是包类型和值打包成接口,并返回结果。

  1. To modify a reflection object, the value must be settable:要修改反射对象,其值必须可设置;
func main() {
    var x float64 = 3.4
    v := reflect.ValueOf(x)
    // panic: reflect: reflect.flag.mustBeAssignable using addressable value
    v.SetFloat(7.1) 
    
    p := reflect.ValueOf(&X)
    // panic: reflect: reflect.flag.mustBeAssignable using addressable value
    p.SetFloat(7.1) 
    
    e := reflect.ValueOf(&X).Elem()
    // OK
    e.SetFloat(7.1) 
}

如果我们想通过反射来修改x,我们必须把我们想要修改的值的指针传给一个反射库。Go 语言的函数调用都是值传递的,所以我们只能先获取指针对应的 reflect.Value,再通过 reflect.Value.Elem 方法迂回的方式得到可以被设置的变量。我们通过如下所示的代码理解这个过程:

func main() {
    i := 1
    v := &i
    *v = 10
}

如果不能直接操作 i 变量修改其持有的值,我们就只能获取 i 变量所在地址并使用 *v 修改所在地址中存储的整数。

相关资料:

[1] Go语言中反射包的实现原理 https://studygolang.com/articles/2157

[2] 4.3反射 https://draveness.me/golang/docs/part2-foundation/ch04-basic/golang-reflect/

相关文章

  • 深入理解Golang反射

    反射 计算机中提到的反射一般是指,程序借助某种手段检查自己结构的一种能力,通常就是借助编程语言中定义的类型(typ...

  • Golang的反射reflect深入理解和示例

    [TOC] Golang的反射reflect深入理解和示例 【记录于2018年2月】 编程语言中反射的概念 在计算...

  • 关于反射

    Golang的反射reflect深入理解和示例 编程语言中反射的概念 在计算机科学领域,反射是指一类应用,它们能够...

  • Golang 反射个人理解

    (value) Elem() 如果value是空接口类型,返回其具体的值如果是指针,返回指向的内容 (type) ...

  • Golang的反射reflect深入理解和示例

    编程语言中反射的概念 在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机...

  • Golang的反射reflect深入理解和示例

    本人认为讲解的最好的文章,在此做个备案。方便以后查询。 微信链接地址: https://mp.weixin.qq....

  • Golang 反射实现依赖注入

    Golang 反射实现依赖注入 Coding/Golang #Golang #Golang/reflect 依赖注...

  • Golang源码之Channel

    引用 图解Golang的channel底层原理 深入理解Golang Channel Go语言设计与实现-Chan...

  • 反射深入理解

    反射就是把我们写的普通Java类中的各种成分映射成对应的Java类。如普通的Java类都有方法,构造方法和字段等成...

  • 深入理解反射

    众所周知,如果没有了java的反射,那么java中的框架将不复存在,所以当我们学好了反射以后对我们日后学习框架是有...

网友评论

      本文标题:深入理解Golang反射

      本文链接:https://www.haomeiwen.com/subject/iualmhtx.html