反射(reflection)是指在运行时,动态获取程序结构信息(元信息)的一种能力,是静态类型语言都支持的一种特性,如Java, golang等。这里主要详细介绍golang reflection相关知识

类型与接口(Types and interfaces)

typeMyIntintvariintvarjMyInt

i 为int类型,j为MyInt类型。虽然i,j底层类型均为int,但它们属于不同类型,没有转换不能相互赋值。

接口类型 interface, 表示一系列方法集合,任意concrete (non-interface) value 只要实现了接口方法,便可赋值给interface

//ReaderistheinterfacethatwrapsthebasicReadmethod.typeReaderinterface{Read(p[]byte)(nint,errerror)}//WriteristheinterfacethatwrapsthebasicWritemethod.typeWriterinterface{Write(p[]byte)(nint,errerror)}varrio.Readerr=os.Stdinr=bufio.NewReader(r)r=new(bytes.Buffer)//andsoon

r变量的静态类型为io.Reader,实际类型可能是File, Buffer类型

interface{}特殊接口类型,没有任何方法,因此任何类型都可赋值给它The representation of an interface

varrio.Readerr=new(bytes.Buffer)

r变量的具体类型是io.Reader,实际类型是bytes.Buffer,那么在运行时,golang是如何实现的呢?

一个interface类型的变量存储了2个信息, 一个值,类型对<value,type> pair:

赋给变量的值(concrete value)

变量值的类型描述符(value's type descriptor)

varrio.Readertty,err:=os.OpenFile("/dev/tty",os.O_RDWR,0)iferr!=nil{returnnil,err}r=tty

接口类型r 的<value, type> pair是(tty,*os.File)

当然r变量的value tty不仅仅实现了io.Reader接口中的Read方法,还实现了io.Writer中的Write方法,因此可以进行

类型断言(type assertion),试图将r 转换为io.Writer

varwio.Writerw=r.(io.Writer)

此时,接口变量w的<value,type>pair 为(tty,*os.File),也就是说r,w 底层value是一样的,可以通过不同的type来暴露不同的方法出来。

继续讨论

varemptyinterface{}empty=w//此处不需要typeassertion,因为任意类型都可以看作实现了emptyinterface的方法

接口变量empty的<value,type> pair 为(tty,*os.File)

Reflection1. Reflection goes from interface value to reflection object.(接口类型---> 反射类型(reflect.Value,reflect.Type))

反射,可以获取interface类型变量的具体信息(<value,concrete type>)

golang 反射包为reflect

//ValueOfreturnsanewValueinitializedtotheconcretevalue//storedintheinterfacei.ValueOf(nil)returnsthezeroValue.funcValueOf(iinterface{})Value//获取pair中的value//TypeOfreturnsthereflectionTypethatrepresentsthedynamictypeofi.//Ifiisanilinterfacevalue,TypeOfreturnsnil.funcTypeOf(iinterface{})Type//获取pair中的concretetype

eg:

varrio.Readerr=os.Stdin//<value,type>:<os.Stdin,*os.File>rValue:=reflect.ValueOf(r)rType:=reflect.TypeOf(r)fmt.Println("value:",rValue)fmt.Println("type:",rType)输出:value:&{0xc04205a000}//指针type:*os.Filevarffloat64f=1.234fmt.Println("fvalue:",reflect.ValueOf(f))fmt.Println("ftype:",reflect.TypeOf(f))输出:fvalue:1.234ftype:float642. Reflection goes from reflection object to interface value. 反射类型(reflect.Value,reflect.Type) --> 接口类型

typeUserstruct{IdintNamestringAgeint}func(uUser)ReflectCallFunc(){fmt.Println("reflectlearn")}user:=User{1,"test",13}variinterface{}i=useruValue:=reflect.ValueOf(i)uType:=reflect.TypeOf(i)fmt.Println("uValue:",uValue)fmt.Println(uValue.Interface())//转换为interface类型,unpackuValue.Interface().(User)fmt.Println(uValue.Type())fmt.Println("uValue,string:",uType.String())fmt.Println("uType:",uType.Name())fori:=0;i<uType.NumField();i++{//获取field信息field:=uType.Field(i)value:=uValue.Field(i).Interface()fmt.Printf("%s:%v=%v\n",field.Name,field.Type,value)}fori:=0;i<uType.NumMethod();i++{//获取method信息method:=uType.Method(i)fmt.Printf("method[%d]=%s\n",i,method.Name)}fmt.Println(uValue.Kind())fmt.Println(uType.Kind())


3. To modify a reflection object, the value must be settable. 通过反射修改变量

varxfloat64=3.4v:=reflect.ValueOf(x)fmt.Println("settabilityofv:",v.CanSet())//print:settabilityofv:falsev.SetFloat(7.1)//Error:willpanic.

不可修改的原因:we pass a copy ofxtoreflect.ValueOf, so the interface value created as the argument toreflect.ValueOfis a copy ofx, notxitself

解决办法,传递指针!!

varxfloat64=3.4p:=reflect.ValueOf(&x)//Note:taketheaddressofx.fmt.Println("typeofp:",p.Type())fmt.Println("settabilityofp:",p.CanSet())print:typeofp:*float64settabilityofp:false//why?p不可set,p指向的内容可set,p指向的内容即*p,如何获得p指向的内容?

reflect.Value 的Elem方法,可以获取value 指向的内容

v:=p.Elem()fmt.Println("settabilityofv:",v.CanSet())//settabilityofv:truev.SetFloat(7.1)fmt.Println(v.Interface())//7.1fmt.Println(x)//7.1


4. Structs 反射操作实例

typeTstruct{AintBstring}t:=T{23,"skidoo"}s:=reflect.ValueOf(&t).Elem()typeOfT:=s.Type()fori:=0;i<s.NumField();i++{f:=s.Field(i)fmt.Printf("%d:%v%s%s=%v\n",i,s.Kind(),typeOfT.Field(i).Name,f.Type(),f.Interface())}fmt.Println("canSet:",s.CanSet())s.Field(0).SetInt(24)s.Field(1).SetString("SunsetStrip")fmt.Println("afterchange:",s.Interface())5. 通过reflect 来调用方法

typeUserstruct{IdintNamestringAgeint}func(uUser)ReflectCallFunc(){fmt.Println("reflectlearn")}func(uUser)FuncHasArgs(namestring,ageint){fmt.Println("FuncHasArgsname:",name,",age:",age,"andorigalUser.Name:",u.Name)}func(uUser)FuncNoArgs(){fmt.Println("FuncNoArgs")}user:=User{1,"test",13}uValue:=reflect.ValueOf(user)uType:=reflect.TypeOf(user)m1:=uValue.MethodByName("FuncHasArgs")m2:=uValue.MethodByName("FuncNoArgs")m,b:=uType.MethodByName("FuncNoArgs")args:=[]reflect.Value{reflect.ValueOf("xiong"),reflect.ValueOf(30)}m1.Call(args)args=make([]reflect.Value,0)m2.Call(args)fmt.Println("m1:",m1)fmt.Println("m2:",m2)fmt.Printf("m:%#v,isfound:%v\n",m,b)fmt.Println(m1)