在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
每种语言的反射模型都不同,并且有些语言根本不支持反射。Golang语言实现了反射,反射机制就是在运行时动态的调用对象的方法和属性,官方自带的reflect包就是反射相关的,只要包含这个包就可以使用。
反射可大大提高程序的灵活性,使得interface{}有更大的发挥余地
反射使用TypeOf和ValueOf函数从接口中获取目标对象信息
用反射修改对象的状态,前提是interface.data是settable,以及pointer-interface
DeepEqual
func DeepEqual(x, y interface{}) bool
用于下列类型同类间的比较,返回为true条件:
array:
slice:length一样并且内部元素都deep equal,引用的array可以不一样
struct:类型一样,内部元素全部deep equal,包括开头小写的字段
interface:分别被赋予deepe qual的值
map:
pointer:地址一样或者指向deepe qual的值
TypeOf和ValueOf
func TypeOf(i interface{}) Type
func ValueOf(i interface{}) Value
举例:
type User struct {
Id int
Name string
Age int
}
type Manager struct {
User
Title string
}
func (u User) Hello(s string) {
fmt.Println("hello, ", s)
}
反射基本操作
var o interface {}
a := 5
o = a
b := o.(int) //得到int类型5
c := reflect.ValueOf(o).Int() //得到int64类型5
func StructInfo(o interface{}) {
t := reflect.TypeOf(o)
fmt.Println("Type:", t.Name())
v := reflect.ValueOf(o)
fmt.Println("Fields:")
for i := 0; i < t.NumField(); i++{
f := t.Field(i)
val := v.Field(i)
fmt.Println(f.Name,f.Type,val)
}
for i := 0; i < t.NumMethod(); i++{
m := t.Method(i)
fmt.Println(m.Name,m.Type)
}
}
反射匿名或嵌入字段
func AnonymousStruct(o interface{}) {
t := reflect.TypeOf(o)
fmt.Println(t.FieldByIndex([]int{0,0}).Name)
}
修改目标对象
func SetInt() {
x := 123
v := reflect.ValueOf(&x)
v.Elem().SetInt(56)
fmt.Println(x)
}
func SetStruct(o interface{}) {
v := reflect.ValueOf(o)
if v.Kind() != reflect.Ptr || !v.Elem().CanSet(){
fmt.Println("can not set")
return
}else {
v = v.Elem()
}
f := v.FieldByName("Name")
if !f.IsValid(){
fmt.Println("have no the name")
return
}
if f.Kind() == reflect.String{
f.SetString("BYE")
}
}
动态调用方法
func Dynamic(o interface{}) {
v := reflect.ValueOf(o)
vm := v.MethodByName("Hello")
args := []reflect.Value{reflect.ValueOf("lilei")}
vm.Call(args)
}
func main() {
u := User{1,"lily",18}
m := Manager{u,"boss"}
StructInfo(u)
AnonymousStruct(m)
SetStruct(&u)
Dynamic(u)
}
Swapper
func Swapper(slice interface{}) func(i, j int)
此方法应用于slice,返回一个方程,可以交换传入的两个索引对应的值
a := []int{0,1,2,3,4,5,6,7}
reflect.Swapper(a)(0,4)
fmt.Println(a) //打印:[4 1 2 3 0 5 6 7]