微信: lijiaocn 创建: 2017/11/06 15:34:13
不同语言的反射模式是不同的。
在golang的官网上有一篇文章很详细的介绍了go语言的反射机制: The Laws of Reflection。
反射是建立在类型之上:
- reflection builds on the type system
golang的变量类型是静态的,在创建变量的时候就已经确定,反射主要与golang的interface类型相关。
在golang的实现中,每个interface变量都有一个对应pair,pair中记录了实际变量的值和类型:
- (value, type)
- value是实际变量值,type是实际变量的类型
例如,创建类型为
的变量,然后将其赋给一个接口变量
- *os.File
:
- r
- tty,
- err: =os.OpenFile("/dev/tty", os.O_RDWR, 0)
- var r io.Reader r = tty
接口变量r的pair中将记录如下信息:
- (tty, *os.File)
这个pair在接口变量的连续赋值过程中是不变的,将接口变量r赋给另一个接口变量w:
- var w io.Writer
- w = r.(io.Writer)
接口变量w的pair与r的pair相同,都是:
- (tty, *os.File)
即使w是空接口类型,pair也是不变的。
pair的存在,是golang中实现反射的前提,理解了pair,就更容易理解反射。
是获取pair中的type,
- reflect.TypeOf()
获取pair中的value:
- reflect.ValueOf()
- package main
- import (
- "fmt"
- "reflect"
- )
- func main() {
- var x float64 = 3.4
- fmt.Println("type: ", reflect.TypeOf(x))
- fmt.Println("type: ", reflect.ValueOf(x))
- }
运行时输出的结果是:
- type: float64
- type: 3.4
pair中的value和type用类型
和
- reflect.Value
描述。
- reflect.Type
package: reflect中有很详细的信息,例如Kind()返回的类型:
- const (
- Invalid Kind = iota
- Bool
- Int
- Int8
- Int16
- Int32
- Int64
- Uint
- Uint8
- Uint16
- Uint32
- Uint64
- Uintptr
- Float32
- Float64
- Complex64
- Complex128
- Array
- Chan
- Func
- Interface
- Map
- Ptr
- Slice
- String
- Struct
- UnsafePointer
- )
类型为”relfect.Value”变量,通过下面的方法可以获得接口变量:
- func(v Value) Interface() interface {}
当收到一个类型为reflect.Value类型的变量时,用下面方式将它转换对应的接口变量,然后进行类型判断:
- y: =v.Interface(). (float64)
之后就可以使用y的成员和方法。
reflect.Value是通过reflect.ValueOf(X)获得的,只有当X是指针的时候,才可以通过reflec.Value修改实际变量X的值。
例如:
- var x float64 = 3.4
- p := reflect.ValueOf(&x) // Note: take the address of x.
- v := p.Elem()
- fmt.Println("type of p:", v.Type())
- fmt.Println("settability of p:", v.CanSet())
- v.SetFloat(77)
传入的是
,需要用p.Elem()获取所指向的Value。v.CantSet()输出的是true,因此可以用
- * float64
修改x的值。
- v.SetFloat()
如果得到了一个类型为reflect.Value的变量,可以通过下面的方式,获得变量的信息。
如果知道v的真实类型,可先转换成interface{},然后转化成对应的类型:
- r: =v.Interface(). (已知的类型)
除了interface{},还可以转换成其它类型:
- func (v Value) Bool() bool
- func (v Value) Bytes() []byte
- func (v Value) Int() int64
- func (v Value) Uint() uint64
- ...
如果不知道v的真实类型,获取它的Type,然后遍历Type的Field,和v的Field:
- t: =v.Type() for i: =0;
- i < v.NumField();
- i++{
- f: =v.Field(i) fmt.Printf("%d: %s %s = %v\n", i, t.Field(i).Name, f.Type(), f.Interface())
- }
来源: https://juejin.im/entry/5a0be642518825329314143d