理解接口包含的(value, type)对很重要golang
Go的接口都是静态类型化的:一个接口类型变量老是保持同一个静态类型,即便在运行时它保存的值的类型发生变化,这些值老是知足这个接口。函数
一个接口存储一个pair:赋值给这个接口变量的具体值,以及这个值的类型描述符.ui
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)
虽然 io.Reader只提供了 Read 方法,可是咱们依然能够得到到具体的 (tty, *os.File) 对, 因此任然可使用这个值得所有信息.this
好比咱们能够将其断言成 io.Writer指针
var w io.Writer w = r.(io.Writer) // w 包含的依然是 (tty, *os.File)
一样能够再赋值给空接口 interface{}code
var empty interface{} empty = w //empty 依然是 (tty, *os.File)
因此咱们老是能够得到这个具体的值,这样就为反射作好准备.对象
使用反射,首先要知道这两个的区别blog
var str string = "this is a string" Type => string Value => this is a string 源码能够看到: //Type 是个接口 type Type interface{ //一些方法 } //Value 是个 struct type Value struct { //属性 } //源码 //rtype 实现了 Type 接口 type rtype struct { //实际使用的时候用的是这个 }
** TypeOf 和 ValueOf 是获取 Type 和 Value 的方法**接口
// TypeOf returns the reflection Type of the value in the interface{}. func TypeOf(i interface{}) Type
当咱们调用reflect.Typeof(x)的时候,x首先被保存到一个空接口中,这个空接口而后被做为参数传递。reflect.Typeof 会把这个空接口拆包(unpack)恢复出类型信息。ip
例如
package main import ( "fmt" "reflect" ) func main() { var x float64 = 3.4 fmt.Println("type:", reflect.TypeOf(x)) fmt.Println("value:", reflect.ValueOf(x)) //Valueof方法会返回一个Value类型的对象 }
type: float64 value: 3.4 //文档 上写的是这样的, 也就是表示值得意思 value: <float64 Value>
从Value到达Type是经过Value中定义的某些方法来实现的
Value 类型有 Type() 方法能够返回这个value的 Type的类型
(这个方法返回的是值的静态类型即static type,也就是说若是定义了type MyInt int64,那么这个函数返回的是MyInt类型而不是int64,看后面那个Kind方法就能够理解了) Type和Value都有一个Kind方法能够返回一个常量用于指示一个项究竟是以什么形式(也就是底层类型即underlying type,继续前面括号里提到的,Kind返回的是int64而不是MyInt)
package main import ( "fmt" "reflect" ) type MyInt int64 func main() { var x MyInt = 3 fmt.Println("type:", reflect.TypeOf(x)) fmt.Println("value:", reflect.ValueOf(x)) //Valueof方法会返回一个Value类型的对象 fmt.Println(reflect.ValueOf(x).Type()) fmt.Println(reflect.TypeOf(x).Kind()) fmt.Println(reflect.ValueOf(x).Kind()) } //结果 type: main.MyInt value: 3 main.MyInt int64 int64
Reflection goes from interface value to reflection object.
keep the API simple
官方:第一个性质是,为了保持API简单,Value的”setter”和“getter”类型的方法操做的是能够包含某个值的最大类型
其实说的就是 如 reflect包中 Int(), Uint(), Float()等方法 返回的都是最大的那个如int64, int64, float64等. SetInt(int64), SetFloat(float64)等.
package main import ( "fmt" "reflect" ) func main() { var x uint8 = 'x' v := reflect.ValueOf(x) fmt.Println("type:", v.Type()) // uint8. fmt.Println("kind is uint8: ", v.Kind() == reflect.Uint8) // true. x = uint8(v.Uint())// v.Uint returns a uint64.看到啦嘛?这个地方必须进行强制类型转换! fmt.Println(reflect.TypeOf(v.Uint())) // } //结果 type: uint8 kind is uint8: true uint64
官方:第二个性质是,反射对象(reflection object)的Kind描述的是底层类型(underlying type),而不是静态类型(static type)
type MyInt int var x MyInt = 7 v := reflect.ValueOf(x) // v.Kind() 为 reflect.Int 即便x的静态类型是MyInt而不是int。换句话说,Kind不能将一个int从一个MyInt中区别出来,可是Type能作到 使用value.Type() 结果是 MyInt
Reflection goes from reflection object to interface value
也就是说反射对象能够逆反射成接口
给定一个reflect.Value,咱们能用Interface方法把它恢复成一个接口值;效果上就是这个Interface方法把类型和值的信息打包成一个接口表示而且返回结果
简单说:Interface方法是Valueof函数的逆
// Interface returns v's value as an interface{}. func (v Value) Interface() interface{}
package main import ( "fmt" "reflect" ) func main() { var x float64 = 3.2 v := reflect.ValueOf(x) y := v.Interface().(float64) // y will have type float64. fmt.Println(y) //3.2 //fmt.Println能够处理interface{}, 因此能够直接 fmt.Println(v.Interface()) // 3.2 //由于是float, 因此也能够用printf,不是不行 fmt.Printf("value is %7.1e\n", v.Interface()) //value is 3.2e+00 }
To modify a reflection object, the value must be settable.
修改反射对象,值必须是可settable的
这段代码会发生panic
var x float64 = 3.4 v := reflect.ValueOf(x) v.SetFloat(7.1) // Error: will panic. //panic: reflect.Value.SetFloat using unaddressable value
问题不是不能寻址, 而是出在v不是settable的.
Settability是Value的一条性质,并且不是全部的Value都具有这条性质.
var x float64 = 3.4 v := reflect.ValueOf(x) fmt.Println("settability of v:", v.CanSet()) //settability of v: false
也就是咱们 reflect.ValueOf创造出的接口值v,只是x的副本,因此不能赋值.
就像咱们使用函数f(x), 传入的x是个副本,咱们不能用传入的x修改原来的值.
除非咱们传入的是f(&x)才能够修改值,一样反射若是想修改值,就要将要修改值得指针传入反射库.
var x float64 = 3.4 p := reflect.ValueOf(&x) // Note: take the address of x.注意这里哦!咱们把x地址传进去了! fmt.Println("type of p:", p.Type()) fmt.Println("settability of p:", p.CanSet()) //结果 type of p: *float64 settability of p: false
咱们传入了x的指针,咱们想设置的是*p,为了获得他咱们使用 value.Elem()来得到具体的
v := p.Elem() fmt.Println("settability of v:", v.CanSet()) //settability of v: true v.SetFloat(7.1) fmt.Println(v.Interface()) //7.1 fmt.Println(x) // 7.1
reflection Values need the address of something in order to modify what they represent 反射Values为了修改它们所表示的东西必需要有这些东西的地址
使用struct 进行反射,最大的问题就是在实例化的时候, 有多是直接赋值struct,而有一些是new出来的 表示的是指针, 这样在反射方法的时候就会有一些问题.
type T struct { A int B string } t := T{23, "skidoo"} s := reflect.ValueOf(&t).Elem() //这里传入的是&t,因此是可设置的, 若是是t,就不能够设置了 typeOfT := s.Type()//把s.Type()返回的Type对象复制给typeofT,typeofT也是一个反射。 for i := 0; i < s.NumField(); i++ { f := s.Field(i)//迭代s的各个域,注意每一个域仍然是反射。 fmt.Printf("%d: %s %s = %v\n", i, typeOfT.Field(i).Name, f.Type(), f.Interface())//提取了每一个域的名字 } //结果 0: A int = 23 1: B string = skidoo
** 这里T中首字母都是大写的(可导出的)**,只有可导出的域才是settable的.
由于传入的是指针,因此是可修改的,那么咱们能够修改这些值.
s.Field(0).SetInt(77) s.Field(1).SetString("Sunset Strip") fmt.Println("t is now", t) t is now {77 Sunset Strip}
或者这样也是同样的
t := new(T) t.A = 23 t.B = "skidoo" s := reflect.ValueOf(t).Elem() //由于new完表示的就是指针