GoLang反射

x33g5p2x  于2022-08-17 转载在 其他  
字(17.1k)|赞(0)|评价(0)|浏览(678)

前言

反射是 Go 语言比较重要的特性。虽然在大多数的应用和服务中并不常见,但是很多框架都依赖 Go 语言的反射机制实现简化代码的逻辑。因为 Go 语言的语法元素很少、设计简单,所以它没有特别强的表达能力,但是 Go 语言的 reflect 包能够弥补它在语法上的一些劣势。

reflect 实现了运行时的反射能力,能够让程序操作不同类型的对象。反射包中有两对非常重要的函数和类型,reflect.TypeOf 能获取类型信息,reflect.ValueOf 能获取数据的运行时表示,另外两个类型是 Type 和 Value,它们与函数是一一对应的关系:

类型 Type 是反射包定义的一个接口,我们可以使用 reflect.TypeOf 函数获取任意变量的的类型,Type 接口中定义了一些有趣的方法,MethodByName 可以获取当前类型对应方法的引用、Implements 可以判断当前类型是否实现了某个接口:

  1. type Type interface {
  2. Align() int
  3. FieldAlign() int
  4. Method(int) Method
  5. MethodByName(string) (Method, bool)
  6. NumMethod() int
  7. ...
  8. Implements(u Type) bool
  9. ...
  10. }

反射包中 Value 的类型与 Type 不同,它被声明成了结构体。这个结构体没有对外暴露的字段,但是提供了获取或者写入数据的方法:

  1. type Value struct {
  2. // contains filtered or unexported fields
  3. }
  4. func (v Value) Addr() Value
  5. func (v Value) Bool() bool
  6. func (v Value) Bytes() []byte
  7. ...

反射包中的所有方法基本都是围绕着 Type 和 Value 这两个类型设计的。我们通过 reflect.TypeOf、reflect.ValueOf 可以将一个普通的变量转换成『反射』包中提供的 Type 和 Value,随后就可以使用反射包中的方法对它们进行复杂的操作。

三大法则

运行时反射是程序在运行期间检查其自身结构的一种方式。反射带来的灵活性是一把双刃剑,反射作为一种元编程方式可以减少重复代码,但是过量的使用反射会使我们的程序逻辑变得难以理解并且运行缓慢。我们在这一节中会介绍 Go 语言反射的三大法则,其中包括:

  • 从 interface{} 变量可以反射出反射对象;
  • 从反射对象可以获取 interface{} 变量;
  • 要修改反射对象,其值必须可设置;

第一法则

反射的第一法则是我们能将 Go 语言的 interface{} 变量转换成反射对象。很多读者可能会对这以法则产生困惑 ,为什么是从 interface{} 变量到反射对象?

当我们执行 reflect.ValueOf(1) 时,虽然看起来是获取了基本类型 int 对应的反射类型,但是由于 reflect.TypeOf、reflect.ValueOf 两个方法的入参都是 interface{} 类型,所以在方法执行的过程中发生了类型转换。

Go 语言的函数调用都是值传递的,变量会在函数调用时进行类型转换。基本类型 int 会转换成 interface{} 类型,这也就是为什么第一条法则是『从接口到反射对象』。

上面提到的 reflect.TypeOf 和 reflect.ValueOf 函数就能完成这里的转换,如果我们认为 Go 语言的类型和反射类型处于两个不同的『世界』,那么这两个函数就是连接这两个世界的桥梁。

我们通过以下例子简单介绍这两个函数的作用,reflect.TypeOf 获取了变量 author 的类型,reflect.ValueOf 获取了变量的值 draven。如果我们知道了一个变量的类型和值,那么就意味着知道了这个变量的全部信息。

  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. )
  6. func main() {
  7. author := "draven"
  8. fmt.Println("TypeOf author:", reflect.TypeOf(author))
  9. fmt.Println("ValueOf author:", reflect.ValueOf(author))
  10. }
  11. $ go run main.go
  12. TypeOf author: string
  13. ValueOf author: draven

有了变量的类型之后,我们可以通过 Method 方法获得类型实现的方法,通过 Field 获取类型包含的全部字段。对于不同的类型,我们也可以调用不同的方法获取相关信息:

  • 结构体:获取字段的数量并通过下标和字段名获取字段 StructField;
  • 哈希表:获取哈希表的 Key 类型;
  • 函数或方法:获取入参和返回值的类型;

总而言之,使用 reflect.TypeOf 和 reflect.ValueOf 能够获取 Go 语言中的变量对应的反射对象。一旦获取了反射对象,我们就能得到跟当前类型相关数据和操作,并可以使用这些运行时获取的结构执行方法。

第二法则

反射的第二法则是我们可以从反射对象可以获取 interface{} 变量。既然能够将接口类型的变量转换成反射对象,那么一定需要其他方法将反射对象还原成接口类型的变量,reflect 中的 reflect.Value.Interface 方法就能完成这项工作:

不过调用 reflect.Value.Interface 方法只能获得 interface{} 类型的变量,如果想要将其还原成最原始的状态还需要经过如下所示的显式类型转换:

  1. v := reflect.ValueOf(1)
  2. v.Interface().(int)

从反射对象到接口值的过程就是从接口值到反射对象的镜面过程,两个过程都需要经历两次转换:

从接口值到反射对象:

  • 从基本类型到接口类型的类型转换;
  • 从接口类型到反射对象的转换;

从反射对象到接口值:

  • 反射对象转换成接口类型;
  • 通过显式类型转换变成原始类型;

当然不是所有的变量都需要类型转换这一过程。如果变量本身就是 interface{} 类型,那么它不需要类型转换,因为类型转换这一过程一般都是隐式的,所以我不太需要关心它,只有在我们需要将反射对象转换回基本类型时才需要显式的转换操作。

第三法则

Go 语言反射的最后一条法则是与值是否可以被更改有关,如果我们想要更新一个 reflect.Value,那么它持有的值一定是可以被更新的,假设我们有以下代码:

  1. func main() {
  2. i := 1
  3. v := reflect.ValueOf(i)
  4. v.SetInt(10)
  5. fmt.Println(i)
  6. }
  7. $ go run reflect.go
  8. panic: reflect: reflect.flag.mustBeAssignable using unaddressable value
  9. goroutine 1 [running]:
  10. reflect.flag.mustBeAssignableSlow(0x82, 0x1014c0)
  11. /usr/local/go/src/reflect/value.go:247 +0x180
  12. reflect.flag.mustBeAssignable(...)
  13. /usr/local/go/src/reflect/value.go:234
  14. reflect.Value.SetInt(0x100dc0, 0x414020, 0x82, 0x1840, 0xa, 0x0)
  15. /usr/local/go/src/reflect/value.go:1606 +0x40
  16. main.main()
  17. /tmp/sandbox590309925/prog.go:11 +0xe0

运行上述代码会导致程序崩溃并报出 reflect: reflect.flag.mustBeAssignable using unaddressable value 错误,仔细思考一下就能够发现出错的原因,Go 语言的函数调用都是传值的,所以我们得到的反射对象跟最开始的变量没有任何关系,所以直接对它修改会导致崩溃。

想要修改原有的变量只能通过如下的方法:

  1. func main() {
  2. i := 1
  3. v := reflect.ValueOf(&i)
  4. v.Elem().SetInt(10)
  5. fmt.Println(i)
  6. }
  7. $ go run reflect.go
  8. 10
  • 调用 reflect.ValueOf 函数获取变量指针;
  • 调用 reflect.Value.Elem 方法获取指针指向的变量;
  • 调用 reflect.Value.SetInt 方法更新变量的值:由于 Go 语言的函数调用都是值传递的,所以我们只能先获取指针对应的 reflect.Value,再通过 reflect.Value.Elem 方法迂回的方式得到可以被设置的变量,我们通过如下所示的代码理解这个过程:
  1. func main() {
  2. i := 1
  3. v := &i
  4. *v = 10
  5. }

如果不能直接操作 i 变量修改其持有的值,我们就只能获取 i 变量所在地址并使用 *v 修改所在地址中存储的整数。

API总结

反射类型

  1. //reflect/type.go
  2. type Type interface {
  3. // 该类型内存分配大小(内存对齐单位子节)
  4. Align() int
  5. // 该类型作为结构体字段时内存分配大小(内存对齐单位子节)
  6. FieldAlign() int
  7. // 根据index in [0, NumMethod())获取方法 按lexicographic排序
  8. Method(int) Method
  9. // 根据方法名获取方法
  10. MethodByName(string) (Method, bool)
  11. // 获取所有可用方法数量
  12. // 接口类型 获取包含未导出方法
  13. NumMethod() int
  14. // 返回类型名,未定义则为空
  15. Name() string
  16. // 返回类型所在包名,未定义则为空
  17. PkgPath() string
  18. // 错误类型所需子节数 unsafe.Sizeof.
  19. Size() uintptr
  20. // 返回类型名称字符串
  21. String() string
  22. // 返回此类型的kind类型
  23. Kind() Kind
  24. // 返回是否实现了u接口
  25. Implements(u Type) bool
  26. // 返回类型的值是否可分配给类型u
  27. AssignableTo(u Type) bool
  28. // 返回类型的值是否可以转换为u类型
  29. ConvertibleTo(u Type) bool
  30. // 返回类型的值是否可对比
  31. Comparable() bool
  32. // Methods applicable only to some types, depending on Kind.
  33. // The methods allowed for each kind are:
  34. //
  35. // Int*, Uint*, Float*, Complex*: Bits
  36. // Array: Elem, Len
  37. // Chan: ChanDir, Elem
  38. // Func: In, NumIn, Out, NumOut, IsVariadic.
  39. // Map: Key, Elem
  40. // Ptr: Elem
  41. // Slice: Elem
  42. // Struct: Field, FieldByIndex, FieldByName, FieldByNameFunc, NumField
  43. // Bits returns the size of the type in bits.
  44. // It panics if the type's Kind is not one of the
  45. // sized or unsized Int, Uint, Float, or Complex kinds.
  46. Bits() int
  47. // Elem返回类型的元素类型
  48. // 不是 Array, Chan, Map, Ptr, or Slice. panic
  49. Elem() Type
  50. // --------------- struct ------------------------
  51. // 字段返回结构类型的第i个字段。
  52. // 不是struct 或者下表越界 painc
  53. Field(i int) StructField
  54. // 字段返回嵌套结构类型的第i个字段。
  55. // 不是struct 或者下表越界 painc
  56. FieldByIndex(index []int) StructField
  57. // 按名称返回字段
  58. FieldByName(name string) (StructField, bool)
  59. // 按过滤方法返回匹配字段
  60. FieldByNameFunc(match func(string) bool) (StructField, bool)
  61. // 返回结构体字段总数
  62. // 不是 Struct panic.
  63. NumField() int
  64. // --------------- struct ------------------------
  65. // --------------- func --------------------
  66. //返回函数类型第i的输入参数
  67. // 不是Func painc
  68. In(i int) Type
  69. // 返回方法输入参数总数
  70. // 不是Func painc
  71. NumIn() int
  72. // 返回函数输出参数总数
  73. // 不是Func painc
  74. NumOut() int
  75. // 返回函数类型第i的输出参数
  76. // 不是Func painc
  77. Out(i int) Type
  78. // 返回函数是否包含可变参数
  79. // 不是Func painc
  80. IsVariadic() bool
  81. // --------------- func --------------------
  82. // --------------- Map --------------------
  83. // 返回map的key类型
  84. // 不是Map panic
  85. Key() Type
  86. // --------------- Map --------------------
  87. // --------------- Array --------------------
  88. // 返回数组类型的长度
  89. // 不是Array panic
  90. Len() int
  91. // --------------- Array --------------------
  92. // --------------- chan --------------------
  93. // 返回chan类型的方向,不是chan会panic
  94. ChanDir() ChanDir
  95. // --------------- chan --------------------
  96. common() *rtype
  97. uncommon() *uncommonType
  98. }

反射对象

  1. //reflect/value.go
  2. type Value struct {
  3. // 值的类型
  4. typ *rtype
  5. // 数据指针
  6. // flagIndir设置时
  7. ptr unsafe.Pointer
  8. // flag保存有关该值的元数据
  9. flag
  10. }
  11. // 返回value是否可以被寻址
  12. func (v Value) CanAddr() bool
  13. // 类似& value寻址返回包装value
  14. func (v Value) Addr() Value
  15. // 返回value是否可以被修改 需要CanAddr
  16. func (v Value) CanSet() bool
  17. // 类似* value解引用后返回包装value
  18. // 需要prt interface
  19. func (v Value) Elem() Value
  20. // 方法调用
  21. func (v Value) Call(in []Value) []Value
  22. // 方法调用 可变参数使用数组传入
  23. func (v Value) CallSlice(in []Value) []Value
  24. func (v Value) TryRecv() (x Value, ok bool)
  25. func (v Value) Recv() (x Value, ok bool)
  26. func (v Value) TrySend(x Value) bool
  27. func (v Value) Send(x Value)
  28. func (v Value) Close()
  29. func (v Value) Field(i int) Value
  30. func (v Value) FieldByIndex(index []int) Value
  31. func (v Value) FieldByName(name string) Value
  32. func (v Value) FieldByNameFunc(match func(string) bool) Value
  33. func (v Value) Method(i int) Value
  34. func (v Value) NumMethod() int
  35. func (v Value) NumField() int
  36. func (v Value) MethodByName(name string) Value
  37. func (v Value) Index(i int) Value
  38. func (v Value) Type() Type
  39. func (v Value) Kind() Kind
  40. func (v Value) Convert(t Type) Value
  41. func (v Value) UnsafeAddr() uintptr
  42. // 返回子节数组
  43. func (v Value) Bytes() []byte
  44. func (v Value) SetBytes(x []byte)
  45. // 返回string类型
  46. func (v Value) String() string
  47. func (v Value) SetString(x string)
  48. // 返回interface类型
  49. func (v Value) CanInterface() bool
  50. func (v Value) Interface() (i interface{})
  51. func (v Value) InterfaceData() [2]uintptr
  52. func (v Value) Set(x Value)
  53. // 返回float64
  54. func (v Value) Float() float64
  55. func (v Value) SetFloat(x float64)
  56. func (v Value) OverflowFloat(x float64) bool
  57. // 返回int64
  58. func (v Value) Int() int64
  59. func (v Value) SetInt(x int64)
  60. func (v Value) OverflowInt(x int64) bool
  61. // 返回uint64
  62. func (v Value) Uint() uint64
  63. func (v Value) SetUint(x uint64)
  64. func (v Value) OverflowUint(x uint64) bool
  65. // 返回bool
  66. func (v Value) Bool() bool
  67. func (v Value) SetBool(x bool)
  68. // 返回complex128
  69. func (v Value) Complex() complex128
  70. func (v Value) SetComplex(x complex128)
  71. func (v Value) OverflowComplex(x complex128) bool
  72. // map操作
  73. func (v Value) SetMapIndex(key, elem Value)
  74. func (v Value) MapIndex(key Value) Value
  75. func (v Value) MapKeys() []Value
  76. func (v Value) MapRange() *MapIter
  77. // chan func interface map ptr slice 返回值是否位nil
  78. func (v Value) IsNil() bool
  79. // 返回value本身是否有效
  80. func (v Value) IsValid() bool
  81. // 返回value是否位该对应类型的零值
  82. func (v Value) IsZero() bool
  83. func (v Value) Len() int
  84. func (v Value) SetLen(n int)
  85. func (v Value) Cap() int
  86. func (v Value) SetCap(n int)
  87. func (v Value) Pointer() uintptr
  88. func (v Value) SetPointer(x unsafe.Pointer)
  89. func (v Value) Slice(i, j int) Value
  90. func (v Value) Slice3(i, j, k int) Value
  91. type flag uintptr
  92. const (
  93. // tflagUncommon means that there is a pointer, *uncommonType,
  94. // just beyond the outer type structure.
  95. //
  96. // For example, if t.Kind() == Struct and t.tflag&tflagUncommon != 0,
  97. // then t has uncommonType data and it can be accessed as:
  98. //
  99. // type tUncommon struct {
  100. // structType
  101. // u uncommonType
  102. // }
  103. // u := &(*tUncommon)(unsafe.Pointer(t)).u
  104. tflagUncommon tflag = 1 << 0
  105. // tflagExtraStar means the name in the str field has an
  106. // extraneous '*' prefix. This is because for most types T in
  107. // a program, the type *T also exists and reusing the str data
  108. // saves binary size.
  109. tflagExtraStar tflag = 1 << 1
  110. // tflagNamed means the type has a name.
  111. tflagNamed tflag = 1 << 2
  112. // tflagRegularMemory means that equal and hash functions can treat
  113. // this type as a single region of t.size bytes.
  114. tflagRegularMemory tflag = 1 << 3
  115. )
  116. // 实现Type接口
  117. type rtype struct {
  118. size uintptr
  119. ptrdata uintptr // number of bytes in the type that can contain pointers
  120. hash uint32 // hash of type; avoids computation in hash tables
  121. tflag tflag // extra type information flags
  122. align uint8 // alignment of variable with this type
  123. fieldAlign uint8 // alignment of struct field with this type
  124. kind uint8 // enumeration for C
  125. // function for comparing objects of this type
  126. // (ptr to object A, ptr to object B) -> ==?
  127. equal func(unsafe.Pointer, unsafe.Pointer) bool
  128. gcdata *byte // garbage collection data
  129. str nameOff // string form
  130. ptrToThis typeOff // type for pointer to this type, may be zero
  131. }
  132. // 获取当前类型名称
  133. func (t *rtype) String() string {
  134. s := t.nameOff(t.str).name()
  135. if t.tflag&tflagExtraStar != 0 {
  136. return s[1:]
  137. }
  138. return s
  139. }
  140. // reflect/value.go
  141. type emptyInterface struct {
  142. typ *rtype
  143. word unsafe.Pointer
  144. }

反射种类

  1. type Kind uint
  2. const (
  3. Invalid Kind = iota // 非法类型
  4. Bool // 布尔型
  5. Int // 有符号整型
  6. Int8 // 有符号8位整型
  7. Int16 // 有符号16位整型
  8. Int32 // 有符号32位整型
  9. Int64 // 有符号64位整型
  10. Uint // 无符号整型
  11. Uint8 // 无符号8位整型
  12. Uint16 // 无符号16位整型
  13. Uint32 // 无符号32位整型
  14. Uint64 // 无符号64位整型
  15. Uintptr // 指针
  16. Float32 // 单精度浮点数
  17. Float64 // 双精度浮点数
  18. Complex64 // 64位复数类型
  19. Complex128 // 128位复数类型
  20. Array // 数组
  21. Chan // 通道
  22. Func // 函数
  23. Interface // 接口
  24. Map // 映射
  25. Ptr // 指针
  26. Slice // 切片
  27. String // 字符串
  28. Struct // 结构体
  29. UnsafePointer // 底层指针
  30. )

使用场景

  • reflect.TypeOf 能获取类型信息
  1. func TypeOf(i interface{}) Type {
  2. eface := *(*emptyInterface)(unsafe.Pointer(&i))
  3. return toType(eface.typ)
  4. }
  5. func toType(t *rtype) Type {
  6. if t == nil {
  7. return nil
  8. }
  9. return t
  10. }
  • reflect.ValueOf 能获取数据的运行时表示
  1. func ValueOf(i interface{}) Value {
  2. if i == nil {
  3. return Value{}
  4. }
  5. // 当前值逃逸堆上
  6. escapes(i)
  7. return unpackEface(i)
  8. }
  9. func unpackEface(i interface{}) Value {
  10. e := (*emptyInterface)(unsafe.Pointer(&i))
  11. t := e.typ
  12. if t == nil {
  13. return Value{}
  14. }
  15. f := flag(t.Kind())
  16. if ifaceIndir(t) {
  17. f |= flagIndir
  18. }
  19. return Value{t, e.word, f}
  20. }
  1. // 获取反射对象
  2. hello := "hello"
  3. fmt.Println( reflect.TypeOf(hello),reflect.ValueOf(hello))
  4. fmt.Printf("%T %v",hello,hello)
  5. //string hello
  6. //string hello
  7. //反射对象获取值
  8. // reflect.Value -> interface{}(reflect.Inerface) -> type
  9. // type -> interface{} -> reflect.Value(reflect.ValueOf)
  10. v := reflect.ValueOf(1)
  11. i := v.Interface().(int)
  12. fmt.Printf("%T %v \n",v,v)
  13. fmt.Printf("%T %v \n",i,i)
  14. //reflect.Value 1
  15. //int 1
  16. //修改反射对象
  17. a := 1
  18. v1 := reflect.ValueOf(&a)
  19. v1.Elem().SetInt(10)
  20. fmt.Printf("%T %v \n",a,a)
  21. // 等价 v1:=&a *v1=10
  22. //int 10

接口

获取一个接口的type reflect.TypeOf((*<interface>)(nil)).Elem()

  1. type Type struct{
  2. // 根据index in [0, NumMethod())获取方法 按lexicographic排序
  3. Method(int) Method
  4. // 根据方法名获取方法
  5. MethodByName(string) (Method, bool)
  6. // 获取所有可用方法数量
  7. // 接口类型 获取包含未导出方法
  8. NumMethod() int
  9. }

例子

  1. package main
  2. import (
  3. "reflect"
  4. )
  5. type i interface {
  6. F1() string
  7. F3() string
  8. }
  9. type s struct {
  10. h string
  11. Name string
  12. Type int `json:"type" id:"100"`
  13. }
  14. func (h s) F1() string {
  15. return h.Name
  16. }
  17. func (h s) f2() string {
  18. return h.Name
  19. }
  20. func (h *s) F3() string {
  21. return h.Name
  22. }
  23. func main() {
  24. t1 := reflect.TypeOf((*i)(nil)).Elem()
  25. s1 := reflect.TypeOf(&s{})
  26. s2 := reflect.TypeOf(s{})
  27. println(s1.Implements(t1))
  28. println(s2.Implements(t1))
  29. println(t1.Align())
  30. println(t1.FieldAlign())
  31. println(t1.NumMethod())
  32. for i := 0; i < t1.NumMethod(); i++ {
  33. f := t1.Method(i)
  34. println("---------")
  35. println(f.Name)
  36. println(f.Type.String())
  37. println(f.Index)
  38. println(f.Func.String())
  39. println("---------")
  40. }
  41. m1, b := t1.MethodByName("F1")
  42. println(b, m1.Name)
  43. }
  44. // true
  45. // false
  46. // 8
  47. // 8
  48. // 2
  49. // ---------
  50. // F1
  51. // func() string
  52. // 0
  53. // <invalid Value>
  54. // ---------
  55. // ---------
  56. // F3
  57. // func() string
  58. // 1
  59. // <invalid Value>
  60. // ---------
  61. // true F1

结构体

  1. // reflect/type.go
  2. // StructField
  3. type StructField struct {
  4. Name string // 字段名
  5. PkgPath string // 字段路径
  6. Type Type // 字段反射类型对象
  7. Tag StructTag // 字段的结构体标签
  8. Offset uintptr // 字段在结构体中的相对偏移
  9. Index []int // Type.FieldByIndex中的返回的索引值
  10. Anonymous bool // 是否为匿名字段
  11. }
  12. // StructTag
  13. type StructTag string
  14. //根据 Tag 中的键获取对应的值
  15. func (tag StructTag) Get(key string) string {}
  16. //根据 Tag 中的键,查询值是否存在
  17. func (tag StructTag) Lookup(key string) (value string, ok bool) {}
  18. // 获取StructField
  19. type Type interface {
  20. // 该类型作为结构体字段时内存分配大小(内存对齐单位子节)
  21. FieldAlign() int
  22. // 根据index in [0, NumMethod())获取方法 按lexicographic排序
  23. Method(int) Method
  24. // 根据方法名湖区方法
  25. MethodByName(string) (Method, bool)
  26. // 获取所有可用方法数量
  27. // 接口类型 获取包含未导出方法
  28. NumMethod() int
  29. // 返回是否实现了u接口
  30. Implements(u Type) bool
  31. // 返回类型的值是否可分配给类型u
  32. AssignableTo(u Type) bool
  33. // 返回类型的值是否可以转换为u类型
  34. ConvertibleTo(u Type) bool
  35. // --------------- struct ------------------------
  36. // 字段返回结构类型的第i个字段。
  37. // 不是struct 或者下表越界 painc
  38. Field(i int) StructField
  39. // 字段返回嵌套结构类型的第i个字段。
  40. // 不是struct 或者下表越界 painc
  41. FieldByIndex(index []int) StructField
  42. // 按名称返回字段
  43. FieldByName(name string) (StructField, bool)
  44. // 按过滤方法返回匹配字段
  45. FieldByNameFunc(match func(string) bool) (StructField, bool)
  46. // 返回结构体字段总数
  47. // 不是 Struct panic.
  48. NumField() int
  49. // --------------- struct ------------------------
  50. }

例子

  1. package main
  2. import (
  3. "reflect"
  4. "strings"
  5. )
  6. type i interface{
  7. F1() string
  8. }
  9. type s struct {
  10. h string
  11. Name string
  12. Type int `json:"type" id:"100"`
  13. }
  14. func (h s)F1() string {
  15. return h.Name
  16. }
  17. func (h s)f2() string {
  18. return h.Name
  19. }
  20. func (h *s)F3() string {
  21. return h.Name
  22. }
  23. func main() {
  24. h := reflect.TypeOf(s{})
  25. hptr:=reflect.TypeOf(&s{})
  26. i1:= reflect.TypeOf((*i)(nil)).Elem()
  27. println(h.Align())
  28. println(h.FieldAlign())
  29. println(h.NumField())
  30. println(h.NumMethod())
  31. println(h.AssignableTo(i1))
  32. println(h.Implements(i1))
  33. println(h.ConvertibleTo(i1))
  34. println(hptr.AssignableTo(i1))
  35. println(hptr.Implements(i1))
  36. println(hptr.ConvertibleTo(i1))
  37. for i:=0;i<h.NumField();i++{
  38. f:=h.Field(i)
  39. println("---------")
  40. println(f.Name)
  41. println(f.Type.FieldAlign())
  42. println(f.Type.String())
  43. println(f.Index)
  44. println(f.Anonymous)
  45. println(f.Offset)
  46. println(f.Tag)
  47. println("---------")
  48. }
  49. for i:=0;i<h.NumMethod();i++{
  50. f:=h.Method(i)
  51. println("---------")
  52. println(f.Name)
  53. println(f.Type.String())
  54. println(f.Index)
  55. println(f.Func.String())
  56. println("---------")
  57. }
  58. m1, b := h.MethodByName("f2")
  59. println(b,m1.Name)
  60. s1 ,b := h.FieldByName("h")
  61. println(b,s1.Name)
  62. s2,b:=h.FieldByNameFunc(func(s2 string) bool {
  63. // 必须唯一匹配
  64. return strings.Contains(s2,"e")
  65. })
  66. println(b,s2.Name)
  67. }
  68. // 8
  69. // 8
  70. // 3
  71. // 1
  72. // true
  73. // true
  74. // true
  75. // ---------
  76. // h
  77. // 8
  78. // string
  79. // [1/1]0xc00001c0c0
  80. // false
  81. // 0
  82. // ---------
  83. // ---------
  84. // Name
  85. // 8
  86. // string
  87. // [1/1]0xc00001c0c8
  88. // false
  89. // 16
  90. // ---------
  91. // ---------
  92. // Type
  93. // 8
  94. // int
  95. // [1/1]0xc00001c0d0
  96. // false
  97. // 32
  98. // json:"type" id:"100"
  99. // ---------
  100. // ---------
  101. // F1
  102. // func(main.s) string
  103. // 0
  104. // <func(main.s) string Value>
  105. // ---------
  106. // false
  107. // true h
  108. // false

指针

  • 通过elem()获得指针指向的类型
  1. // 获取StructField
  2. type Type interface {
  3. // Elem返回类型的元素类型
  4. // 不是 Array, Chan, Map, Ptr, or Slice. panic
  5. Elem() Type
  6. }

例子

  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. )
  6. func main() {
  7. s:=&h{Name:"hello"}
  8. v2 := reflect.TypeOf(s)
  9. fmt.Printf("%s %s \n",v2.Name(),v2.Kind())
  10. fmt.Printf("%s %s \n",v2.Elem().Name(),v2.Elem().Kind())
  11. }
  12. // ptr
  13. // h struct

函数

  1. func Type interface {
  2. // --------------- func --------------------
  3. //返回函数类型第i的输入参数
  4. // 不是Func painc
  5. In(i int) Type
  6. // 返回方法输入参数总数
  7. // 不是Func painc
  8. NumIn() int
  9. // 返回函数输出参数总数
  10. // 不是Func painc
  11. NumOut() int
  12. // 返回函数类型第i的输出参数
  13. // 不是Func painc
  14. Out(i int) Type
  15. // 返回函数是否包含可变参数
  16. // 不是Func painc
  17. IsVariadic() bool
  18. // --------------- func --------------------
  19. }
  20. func Value struct{}
  21. // 方法调用
  22. func (v Value) Call(in []Value) []Value
  23. // 方法调用 可变参数使用数组传入
  24. func (v Value) CallSlice(in []Value) []Value

例子

  1. package main
  2. import (
  3. "reflect"
  4. )
  5. func main() {
  6. h := func(p1 int, p2 ...string) string { return fmt.Sprint(p1, p2) }
  7. t := reflect.TypeOf(h)
  8. v := reflect.ValueOf(h)
  9. println(t.IsVariadic()) // 是否包含可变参数
  10. println(t.Kind().String())
  11. println(t.NumIn()) // 输入参数
  12. for i := 0; i < t.NumIn(); i++ {
  13. p := t.In(i) // 第i个输入参数
  14. println(p.Kind().String())
  15. }
  16. println(t.NumOut()) // 输出参数
  17. for i := 0; i < t.NumOut(); i++ {
  18. o := t.Out(i) // 第i个输出参数
  19. println(o.Kind().String())
  20. }
  21. // 参数调用
  22. call := v.Call([]reflect.Value{reflect.ValueOf(1), reflect.ValueOf("1"), reflect.ValueOf("1")})
  23. for _, value := range call {
  24. println(value.String())
  25. }
  26. // 可变参数调用
  27. calls := v.CallSlice([]reflect.Value{reflect.ValueOf(1), reflect.ValueOf([]string{"1", ""})})
  28. for _, value := range calls {
  29. println(value.String())
  30. }
  31. }
  32. //true
  33. //func
  34. //2
  35. //int
  36. //slice
  37. //1
  38. // string
  39. // 1 [1 1]
  40. // 1 [1]

函数调用原理

  1. 1.通过 reflect.funcLayout 计算当前函数需要的参数和返回值的栈布局,也就是每一 个参数和返回值所占的空间大小;
  2. 2.如果当前函数有返回值,需要为当前函数的参数和返回值分配一片内存空间 args
  3. 3.如果当前函数是方法,需要向将方法的接收接收者者拷贝到 args 内存中;
  4. 4.将所有函数的参数按照顺序依次拷贝到对应 args 内存中
  5. a.使用 reflect.funcLayout 返回的参数计算参数在内存中的位置;
  6. b.将参数拷贝到内存空间中;
  7. 5.call(frametype, fn, args, uint32(frametype.size), uint32(retOffset))
  8. a.frametype 栈类型
  9. b.fn 函数指针
  10. c.args 参数内存空间
  11. d.uint32(frametype.size) 栈大小
  12. e.uint32(retOffset) 返回值偏移量

函数返回原理

  1. 1.如果函数没有任何返回值,会直接清空 args 中的全部内容来释放内存空间;
  2. 2.如果当前函数有返回值;
  3. a.将 args 中与输入参数有关的内存空间清空;
  4. b.创建一个 nout 长度的切片用于保存由反射对象构成的返回值数组;
  5. c.从函数对象中获取返回值的类型和内存大小,将 args 内存中的数据转换成 reflect.Value 类型并存储到切片中;
  6. var ret []Value
  7. if nout == 0 {
  8. typedmemclr(frametype, args)
  9. framePool.Put(args)
  10. } else {
  11. typedmemclrpartial(frametype, args, 0, retOffset)
  12. ret = make([]Value, nout)
  13. off = retOffset
  14. for i := 0; i < nout; i++ {
  15. tv := t.Out(i)
  16. a := uintptr(tv.Align())
  17. off = (off + a - 1) &^ (a - 1)
  18. if tv.Size() != 0 {
  19. fl := flagIndir | flag(tv.Kind())
  20. ret[i] = Value{tv.common(), add(args, off, "tv.Size() != 0"), fl}
  21. } else {
  22. ret[i] = Zero(tv)
  23. }
  24. off += tv.Size()
  25. }
  26. }
  27. return ret
  28. }

相关文章