可以在运行时动态获取变量的相关信息。 Import (“reflect”)
官方对此有个非常简明的介绍,两句话耐人寻味:
reflect.TypeOf
,获取变量的类型,返回reflect.Type类型 ;reflect.ValueOf
,获取变量的值,返回reflect.Value类型;reflect.Value.Kind
,获取变量的类别,返回一个常量;reflect.Value.Interface()
,转换成interface{}类型;reflect.ValueOf(x).Float()
,获取变量的值;(reflect.ValueOf(x).Int()
,reflect.ValueOf(x).String()
,reflect.ValueOf(x).Bool()
)reflect.Value.SetXX
相关方法,通过反射的来改变变量的值:reflect.Value.SetFloat()
,设置浮点数;reflect.Value.SetInt()
,设置整数;reflect.Value.SetString()
,设置字符串举个例子:
package main
import (
"fmt"
"reflect"
)
func main() {
var x float64 = 3.4
fmt.Println("type:", reflect.TypeOf(x))
v := reflect.ValueOf(x)
fmt.Println("value:", v)
fmt.Println("type:", v.Type())
fmt.Println("kind:", v.Kind())
fmt.Println("value:", v.Float())
fmt.Println(v.Interface())
fmt.Printf("value is %5.2e\n", v.Interface())
y := v.Interface().(float64)
fmt.Println(y)
}
package main
import (
"fmt"
"reflect"
)
func main() {
var a float64
fv := reflect.ValueOf(&a)
//其中fv.Elem()用来获取指针指向的变量,相当于: var a *int; *a = 100
fv.Elem().SetFloat(3.3)
fmt.Printf("%v\n", a)
}
reflect.Value.NumField()
获取结构体中字段的个数reflect.Value.Method(n).Call
来调用结构体中的方法举个例子(通过反射操作结构体):
package main
import (
"fmt"
"reflect"
)
type NotknownType struct {
s1 string
s2 string
s3 string
}
func (n NotknownType) String() string {
return n.s1 + "-" + n.s2 + "-" + n.s3
}
var secret interface{} = NotknownType{"Ada", "Go", "Oberon"}
func main() {
value := reflect.ValueOf(secret) //
typ := reflect.TypeOf(secret) // main.NotknownType
fmt.Println(typ)
knd := value.Kind() // struct
fmt.Println(knd)
for i := 0; i < value.NumField(); i++ {
fmt.Printf("Field %d: %v\n", i, value.Field(i))
//value.Field(i).SetString("C#")
}
results := value.Method(0).Call(nil)
fmt.Println(results) // [Ada - Go - Oberon]
}
package main
import (
"fmt"
"reflect"
)
type T struct {
A int
B string
}
func main() {
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())
}
s.Field(0).SetInt(77)
s.Field(1).SetString("Sunset Strip")
fmt.Println("t is now", t)
}
interface类型有个(value,type)对,而反射就是检查interface的这个(value, type)对的。具体一点说就是Go提供一组方法提取interface的value,提供另一组方法提取interface的type.
反射包里有两个接口类型要先了解一下.
反射第一定律:反射可以将interface类型变量转换成反射对象
package main
import (
"fmt"
"reflect"
)
func main() {
//通过反射获取一个变量的值和类型的
var x float64 = 3.4
t := reflect.TypeOf(x) //t is reflext.Type
fmt.Println("type:", t)
v := reflect.ValueOf(x) //v is reflext.Value
fmt.Println("value:", v)
}
执行结果如下:
注意:反射是针对interface类型变量的,其中TypeOf()和ValueOf()接受的参数都是interface{}类型的,也即x值是被转成了interface传入的。
反射第二定律:反射可以将反射对象还原成interface对象
package main
import (
"fmt"
"reflect"
)
//之所以叫'反射',反射对象与interface对象是可以互相转化的
func main() {
var x float64 = 3.4
v := reflect.ValueOf(x) //v is reflext.Value
var y float64 = v.Interface().(float64)
fmt.Println("value:", y)
}
执行结果如下:
对象x转换成反射对象v,v又通过Interface()接口转换成interface对象,interface对象通过.(float64)类型断言获取float64类型的值。
反射第三定律:反射对象可修改,value值必须是可设置的
通过反射可以将interface类型变量转换成反射对象,可以使用该反射对象设置其持有的值。
reflect.Value
提供了Elem()
方法,可以获得指针向指向的value。看如下代码:
package main
import (
"reflect"
"fmt"
)
func main() {
var x float64 = 3.4
v := reflect.ValueOf(&x)
v.Elem().SetFloat(7.1)
fmt.Println("x :", v.Elem().Interface())
}
执行结果如下图:
对反射的深入理解,个人觉得还需要继续看的内容:
上一篇:06_Go语言进阶学习_ 接口详解
下一篇:08_Go语言进阶学习_ 排序、链表、二叉树