目录反射概述反射基础-go的interface是怎么存储的反射对象-reflect.Type和reflect.Value反射定律Elem方法reflect.Value的Elem...
目录
反射概述反射基础 - go 的 interface 是怎么存储的
反射对象 - reflect.Type 和 reflect.Value
反射定律
Elem 方法
reflect.Value 的 Elem 方法
reflect.Type 的 Elem 方法
Interface 方法
Kind
addressable
获取类型信息 - reflect.Type
概述
通用的 Type 方法
某些类型特定的 Type 方法
创建 reflect.Type 的方式
获取值信息 - reflect.Value
概述
reflect.Value 的方法
创建 reflect.Value 的方式
总结
反射概述
ORMjson.Marshal
反射基础 - go 的 interface 是怎么存储的
interface
vara=1
varbinterface{}=a
bint1bb

beface
typeefacestruct{
_type*_type
dataunsafe.Pointer
}
也就是说,一个 interface{} 中实际上既包含了变量的类型信息,也包含了类型的数据。正因为如此,我们才可以通过反射来获取到变量的类型信息,以及变量的数据信息。
反射对象 - reflect.Type 和 reflect.Value
interface{}reflect.Typereflect.Valuereflect.TypeOfreflect.ValueOf
vara=1 t:=reflect.TypeOf(a) varb="hello" t1:=reflect.ValueOf(b)
TypeOfValueOfinterface{}reflect.Typereflect.Valuereflect.TypeOfreflect.ValueOf

反射定律
在 go 官方博客中关于反射的文章 laws-of-reflection 中,提到了三条反射定律:
interfaceinterfaceCanSet关于这三条定律,官方博客已经有了比较完整的阐述,感兴趣的可以去看一下官方博客的文章。这里简单阐述一下:
反射可以将 interface 类型变量转换成反射对象。
reflect.Typereflect.Valuereflect.TypeOfreflect.ValueOf
vara=1 typeOfA:=reflect.TypeOf(a) valueOfA:=reflect.ValueOf(a)
反射可以将反射对象还原成 interface 对象。
reflect.Value.Interfaceinterfacereflect.ValueOfinterface{}
i:=valueOfA.Interface() fmt.Println(i.(int))
如果要修改反射对象,那么反射对象必须是可设置的(CanSet)。
reflect.Value.CanSetreflect.Value.Set
varxfloat64=3.4
v:=reflect.ValueOf(&x)
fmt.Println("settabilityofv:",v.CanSet())//false
fmt.Println("settabilityofv:",v.Elem().CanSet())//true
reflect.ValueOfreflect.ValueOfreflect.ValueOfxxxx
v.CanSet()falsev.Elem().CanSet()truevv.Elem()xv.CanSet()false
v.Elem().CanSet()truev.Elem()xv.Elem()x

Elem 方法
ElemElemreflect.Valuereflect.TypeElem
reflect.Value 的 Elem 方法
reflect.ValueElemElemreflect.ValueElempanic
vara=1 //panic:reflect:callofreflect.Value.ElemonintValue reflect.ValueOf(a).Elem() //不报错 varb=&a reflect.ValueOf(b).Elem()
interfaceElemifaceefacedata
指针类型:

接口类型:

reflect.Type 的 Elem 方法
reflect.TypeElemreflect.TypeElemreflect.TypeElempanic
示例:
t1:=reflect.TypeOf([3]int{1,2,3})//数组[3]int
fmt.Println(t1.String())//[3]int
fmt.Println(t1.Elem().String())//int
KeyElem
m:=make(map[string]string) t1:=reflect.TypeOf(m) fmt.Println(t1.Key().String())//string
Interface 方法
reflect.ValueInterfaceInterface
var i interface{} = xreflect.ValueOf(x).Interface()iinterface{}
Kind
说到反射,不得不提的另外一个话题就是 go 的类型系统,对于开发者来说,我们可以基于基本类型来定义各种新的类型,如:
//Kind是int
typemyInyint
//Kind是Struct
typePersonstruct{
Namestring
Ageint
}
但是不管我们定义了多少种类型,在 go 看来都是下面的基本类型中的一个:
typeKinduint const( InvalidKind=iota Bool Int Int8 Int16 Int32 Int64 Uint Uint8 Uint16 Uint32 Uint64 Uintptr Float32 Float64 Complex64 Complex128 Array Chan Func Interface Map Pointer Slice String Struct UnsafePointer )
Kindreflect.TypeKindKindreflect.TypeKind
Type 表示的是反射对象(Type 对象是某一个 Kind,通过 Kind() 方法可以获取 Type 的 Kind),Kind 表示的是 go 底层类型系统中的类型。
比如下面的例子:
funcdisplay(pathstring,vreflect.Value){
switchv.Kind(){
casereflect.Invalid:
fmt.Printf("%s=invalid\n",path)
casereflect.Slice,reflect.Array:
fori:=0;i<v.Len();i++{
display(fmt.Sprintf("%s[%d]",path,i),v.Index(i))
}
casereflect.Struct:
fori:=0;i<v.NumField();i++{
fieldPath:=fmt.Sprintf("%s.%s",path,v.Type().Field(i).Name)
display(fieldPath,v.Field(i))
}
casereflect.Map:
for_,key:=rangev.MapKeys(){
display(fmt.Sprintf("%s[%s]",path,formatAny(key)),v.MapIndex(key))
}
casereflect.Pointer:
ifv.IsNil(){
fmt.Printf("%s=nil\n",path)
}else{
display(fmt.Sprintf("(*%s)",path),v.Elem())
}
casereflect.Interface:
ifv.IsNil(){
fmt.Printf("%s=nil\n",path)
}else{
fmt.Printf("%s.type=%s\n",path,v.Elem().Type())
display(path+".value",v.Elem())
}
default:
fmt.Printf("%s=%s\n",path,formatAny(v))
}
}
Struct
addressable
addressableCanAddrCanSet
CanAddrCanAddrtrueAddrCanAddrfalseAddr
CanAddrtruereflect.Valuereflect.ValueCanSetCanSettrue
CanAddrreflect.ValueOf&vCanAddrtruevCanAddrfalse
如果想更详细的了解可以参考一下鸟窝的这篇文章 go addressable 详解。
获取类型信息 - reflect.Type
概述
reflect.Typereflect.TypeOfreflect.Typereflect.Typejsontagtag
通用的 Type 方法
reflect.Typereflect.Type
//Type是Go类型的表示。
//
//并非所有方法都适用于所有类型。
//在调用kind具体方法之前,先使用Kind方法找出类型的种类。因为调用一个方法如果类型不匹配会导致panic
//
//Type类型值是可以比较的,比如用==操作符。所以它可以用做map的key
//如果两个Type值代表相同的类型,那么它们一定是相等的。
typeTypeinterface{
//Align返回该类型在内存中分配时,以字节数为单位的字节数
Align()int
//FieldAlign返回该类型在结构中作为字段使用时,以字节数为单位的字节数
FieldAlign()int
//Method这个方法返回类型方法集中的第i个方法。
//如果i不在[0,NumMethod()]范围内,就会panic。
//对于非接口类型T或*T,返回的Method的Type和Func字段描述了一个函数,
//其第一个参数是接收者,并且只能访问导出的方法。
//对于一个接口类型,返回的Method的Type字段给出的是方法签名,没有接收者,Func字段为nil。
//方法是按字典序顺序排列的。
Method(int)Method
//MethodByName返回类型的方法集中具有该名称的方法和一个指示是否找到该方法的布尔值。
//对于非接口类型T或*T,返回的Method的Type和Func字段描述了一个函数,
//其第一个参数是接收者。
//对于一个接口类型,返回的Method的Type字段给出的是方法签名,没有接收者,Func字段为nil。
MethodByName(string)(Method,bool)
//NumMethod返回使用Method可以访问的方法数量。
//对于非接口类型,它返回导出方法的数量。
//对于接口类型,它返回导出和未导出方法的数量。
NumMethod()int
//Name返回定义类型在其包中的类型名称。
//对于其他(未定义的)类型,它返回空字符串。
Name()string
//PkgPath返回一个定义类型的包的路径,也就是导入路径,导入路径是唯一标识包的类型,如"encoding/base64"。
//如果类型是预先声明的(string,error)或者没有定义(*T,struct{},[]int,或A,其中A是一个非定义类型的别名),包的路径将是空字符串。
PkgPath()string
//Size返回存储给定类型的值所需的字节数。它类似于unsafe.Sizeof.
Size()uintptr
//String返回该类型的字符串表示。
//字符串表示法可以使用缩短的包名。
//(例如,使用base64而不是"encoding/base64")并且它并不能保证类型之间是唯一的。如果是为了测试类型标识,应该直接比较类型Type。
String()string
//Kind返回该类型的具体种类。
Kind()Kind
//Implements表示该类型是否实现了接口类型u。
Implements(uType)bool
//AssignableTo表示该类型的值是否可以分配给类型u。
AssignableTo(uType)bool
//ConvertibleTo表示该类型的值是否可转换为u类型。
ConvertibleTo(uType)bool
//Comparable表示该类型的值是否具有可比性。
Comparable()bool
}
某些类型特定的 Type 方法
panic
typeTypeinterface{
//Bits以bits为单位返回类型的大小。
//如果类型的Kind不属于:sized或者unsizedInt,Uint,Float,或者Complex,会panic。
Bits()int
//ChanDir返回一个通道类型的方向。
//如果类型的Kind不是Chan,会panic。
ChanDir()ChanDir
//IsVariadic表示一个函数类型的最终输入参数是否为一个"..."可变参数。如果是,t.In(t.NumIn()-1)返回参数的隐式实际类型[]T.
//更具体的,如果t代表func(xint,y...float64),那么:
//t.NumIn()==2
//t.In(0)是"int"的reflect.Type反射类型。
//t.In(1)是"[]float64"的reflect.Type反射类型。
//t.IsVariadic()==true
//如果类型的Kind不是Func,IsVariadic会panic
IsVariadic()bool
//Elem返回一个type的元素类型。
//如果类型的Kind不是Array、Chan、Map、Ptr或Slice,就会panic
Elem()Type
//Field返回一个结构类型的第i个字段。
//如果类型的Kind不是Struct,就会panic。
//如果i不在[0,NumField())范围内也会panic。
Field(iint)StructField
//FieldByIndex返回索引序列对应的嵌套字段。它相当于对每一个index调用Field。
//如果类型的Kind不是Struct,就会panic。
FieldByIndex(index[]int)StructField
//FieldByName返回给定名称的结构字段和一个表示是否找到该字段的布尔值。
FieldByName(namestring)(StructField,bool)
//FieldByNameFunc返回一个能满足match函数的带有名称的field字段。布尔值表示是否找到。
FieldByNameFunc(matchfunc(string)bool)(StructField,bool)
//In返回函数类型的第i个输入参数的类型。
//如果类型的Kind不是Func类型会panic。
//如果i不在[0,NumIn())的范围内,会panic。
In(iint)Type
//Key返回一个map类型的key类型。
//如果类型的Kind不是Map,会panic。
Key()Type
//Len返回一个数组类型的长度。
//如果类型的Kind不是Array,会panic。
Len()int
//NumField返回一个结构类型的字段数目。
//如果类型的Kind不是Struct,会panic。
NumField()int
//NumIn返回一个函数类型的输入参数数。
//如果类型的Kind不是Func.NumIn(),会panic。
NumIn()int
//NumOut返回一个函数类型的输出参数数。
//如果类型的Kind不是Func.NumOut(),会panic。
NumOut()int
//Out返回一个函数类型的第i个输出参数的类型。
//如果类型的Kind不是Func,会panic。
//如果i不在[0,NumOut())的范围内,会panic。
Out(iint)Type
}
创建 reflect.Type 的方式
reflect.Type

获取值信息 - reflect.Value
概述
reflect.Valuereflect.Valueinterface{}reflect.ValueOf
同时,我们可以对这些获取到的反射值进行修改。这也是反射的一个重要用途。
reflect.Value 的方法
reflect.ValueSreuct
Set*SetSetBoolSetBytesSetCapSetComplexSetFloatSetIntSetLenSetMapIndexSetPointerSetStringSetUintInterfaceInterfaceDataBoolBytesComplexFloatIntStringUintcomplexIntKindMapIndexMapKeysMapRangeMapSetCloseRecvSendTryRecvTrySendLenCapIndexSliceSlice3NumFieldNumMethodFieldFieldByIndexFieldByNameFieldByNameFuncCanConvertCanComplexCanFloatCanIntCanInterfaceCanUintMethodMethodByNameCallCallSliceIsValidnilIsNilIsZeroOverflowOverflowComplexOverflowFloatOverflowIntOverflowUintAddrCanAddrtrueUnsafeAddrPointerUnsafePointerTypeKindElemConvertLenslicearraychanmapstring
创建 reflect.Value 的方式
reflect.Value

总结
reflect
interface{}interface{}
reflect.Typereflect.Valuereflect.Typereflect.Value
反射三定律:
interfaceinterfaceCanSetreflect.Valuereflect.TypeElem
reflect.TypeElemreflect.Typereflect.ValueElemreflect.Valuereflect.ValueInterfaceinterface{}
TypeKindTypeKindintstringstruct
reflect.Valuereflect.ValueCanSetCanSet
reflect.Typereflect.Value
reflect.Typereflect.Valuereflect.Typereflect.ValueKind