type Kind

Kind代表Type类型值表示的具体分类。零值表示非法分类。

  1. type Kind uint
  2. const (
  3. Invalid Kind = iota
  4. Bool
  5. Int
  6. Int8
  7. Int16
  8. Int32
  9. Int64
  10. Uint
  11. Uint8
  12. Uint16
  13. Uint32
  14. Uint64
  15. Uintptr
  16. Float32
  17. Float64
  18. Complex64
  19. Complex128
  20. Array
  21. Chan
  22. Func
  23. Interface
  24. Map
  25. Ptr
  26. Slice
  27. String
  28. Struct
  29. UnsafePointer
  30. )

type StructField

StructField类型描述结构体中的一个字段的信息

  1. type StructField struct {
  2. // Name是字段的名字。PkgPath是非导出字段的包路径,对导出字段该字段为""。
  3. // 参见http://golang.org/ref/spec#Uniqueness_of_identifiers
  4. Name string
  5. PkgPath string
  6. Type Type // 字段的类型
  7. Tag StructTag // 字段的标签
  8. Offset uintptr // 字段在结构体中的字节偏移量
  9. Index []int // 用于Type.FieldByIndex时的索引切片
  10. Anonymous bool // 是否匿名字段
  11. }

type StructTag

  1. type StructTag string

func (tag StructTag) Get(key string) string 返回标签字符串中键key对应的值。如果标签中没有该键,会返回””
func (tag StructTag) Lookup(key string) (value string, ok bool) 同上,但如果标签中没有该键,ok为false

type Method

Method代表一个方法

  1. type Method struct {
  2. // Name是方法名。PkgPath是非导出字段的包路径,对导出字段该字段为""。
  3. // 结合PkgPath和Name可以从方法集中指定一个方法。
  4. // 参见http://golang.org/ref/spec#Uniqueness_of_identifiers
  5. Name string
  6. PkgPath string
  7. Type Type // 方法类型
  8. Func Value // 方法的值
  9. Index int // 用于Type.Method的索引
  10. }

type Type

Type类型用来表示一个go类型。
不是所有go类型的Type值都能使用所有方法。请参见每个方法的文档获取使用限制。在调用有分类限定的方法时,应先使用Kind方法获知类型的分类。调用该分类不支持的方法会导致运行时的panic。

  1. type Type interface {
  2. // Kind返回该接口的具体分类
  3. Kind() Kind
  4. // Name返回该类型在自身包内的类型名,如果是未命名类型会返回""
  5. Name() string
  6. // PkgPath返回类型的包路径,即明确指定包的import路径,如"encoding/base64"
  7. // 如果类型为内建类型(string, error)或未命名类型(*T, struct{}, []int),会返回""
  8. PkgPath() string
  9. // 返回类型的字符串表示。该字符串可能会使用短包名(如用base64代替"encoding/base64")
  10. // 也不保证每个类型的字符串表示不同。如果要比较两个类型是否相等,请直接用Type类型比较。
  11. String() string
  12. // 返回要保存一个该类型的值需要多少字节;类似unsafe.Sizeof
  13. Size() uintptr
  14. // 返回当从内存中申请一个该类型值时,会对齐的字节数
  15. Align() int
  16. // 返回当该类型作为结构体的字段时,会对齐的字节数
  17. FieldAlign() int
  18. // 如果该类型实现了u代表的接口,会返回真
  19. Implements(u Type) bool
  20. // 如果该类型的值可以直接赋值给u代表的类型,返回真
  21. AssignableTo(u Type) bool
  22. // 如该类型的值可以转换为u代表的类型,返回真
  23. ConvertibleTo(u Type) bool
  24. // 返回该类型可比性
  25. Comparable() bool
  26. // 返回该类型的字位数。如果该类型的Kind不是Int、Uint、Float或Complex,会panic
  27. Bits() int
  28. // 返回array类型的长度,如非数组类型将panic
  29. Len() int
  30. // 返回该类型的元素类型,如果该类型的Kind不是Array、Chan、Map、Ptr或Slice,会panic
  31. Elem() Type
  32. // 返回map类型的键的类型。如非映射类型将panic
  33. Key() Type
  34. // 返回一个channel类型的方向,如非通道类型将会panic
  35. ChanDir() ChanDir
  36. // 返回struct类型的字段数(匿名字段算作一个字段),如非结构体类型将panic
  37. NumField() int
  38. // 返回struct类型的第i个字段的类型,如非结构体或者i不在[0, NumField())内将会panic
  39. Field(i int) StructField
  40. // 返回索引序列指定的嵌套字段的类型,
  41. // 等价于用索引中每个值链式调用本方法,如非结构体将会panic
  42. FieldByIndex(index []int) StructField
  43. // 返回该类型名为name的字段(会查找匿名字段及其子字段),
  44. // 布尔值说明是否找到,如非结构体将panic
  45. FieldByName(name string) (StructField, bool)
  46. // 返回该类型第一个字段名满足函数match的字段,布尔值说明是否找到,如非结构体将会panic
  47. FieldByNameFunc(match func(string) bool) (StructField, bool)
  48. // 如果函数类型的最后一个输入参数是"..."形式的参数,IsVariadic返回真
  49. // 如果这样,t.In(t.NumIn() - 1)返回参数的隐式的实际类型(声明类型的切片)
  50. // 如非函数类型将panic
  51. IsVariadic() bool
  52. // 返回func类型的参数个数,如果不是函数,将会panic
  53. NumIn() int
  54. // 返回func类型的第i个参数的类型,如非函数或者i不在[0, NumIn())内将会panic
  55. In(i int) Type
  56. // 返回func类型的返回值个数,如果不是函数,将会panic
  57. NumOut() int
  58. // 返回func类型的第i个返回值的类型,如非函数或者i不在[0, NumOut())内将会panic
  59. Out(i int) Type
  60. // 返回该类型的方法集中方法的数目
  61. // 匿名字段的方法会被计算;主体类型的方法会屏蔽匿名字段的同名方法;
  62. // 匿名字段导致的歧义方法会滤除
  63. NumMethod() int
  64. // 返回该类型方法集中的第i个方法,i不在[0, NumMethod())范围内时,将导致panic
  65. // 对非接口类型T或*T,返回值的Type字段和Func字段描述方法的未绑定函数状态
  66. // 对接口类型,返回值的Type字段描述方法的签名,Func字段为nil
  67. Method(int) Method
  68. // 根据方法名返回该类型方法集中的方法,使用一个布尔值说明是否发现该方法
  69. // 对非接口类型T或*T,返回值的Type字段和Func字段描述方法的未绑定函数状态
  70. // 对接口类型,返回值的Type字段描述方法的签名,Func字段为nil
  71. MethodByName(string) (Method, bool)
  72. // 内含隐藏或非导出方法
  73. }

func TypeOf(i interface{}) Type TypeOf返回接口中保存的值的类型,TypeOf(nil)会返回nil。
func PtrTo(t Type) Type PtrTo返回类型t的指针的类型。
func ArrayOf(count int, elem Type) Type

  • 返回具有给定计数和元素类型的数组类型。例如,如果t表示int, ArrayOf(5, t)表示[5]int

func ChanOf(dir ChanDir, t Type) Type

  • ChanOf返回具有给定方向和元素类型的通道类型。
  • 例如,如果t表示int, ChanOf(RecvDir, t)表示<-chan int。
  • gc运行时对通道元素类型施加了64 kB的限制。如果t的大小等于或超过这个限制,ChanOf就会恐慌。


func FuncOf(in, out []Type, variadic bool) Type

  • FuncOf返回带有给定参数和结果类型的函数类型。
  • 例如,如果k表示int, e表示string, FuncOf([]Type{k}, []Type{e}, false)表示func(int) string。
  • 可变参数控制函数是否可变。如果in[len(in)-1]不代表切片,且可变值为真,FuncOf会恐慌。

func MapOf(key, elem Type) Type
func SliceOf(t Type) Type
func StructOf(fields []StructField) Type

  1. package main
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "reflect"
  7. )
  8. func main() {
  9. typ := reflect.StructOf([]reflect.StructField{
  10. {
  11. Name: "Height",
  12. Type: reflect.TypeOf(float64(0)),
  13. Tag: `json:"height"`,
  14. },
  15. {
  16. Name: "Age",
  17. Type: reflect.TypeOf(int(0)),
  18. Tag: `json:"age"`,
  19. },
  20. })
  21. v := reflect.New(typ).Elem()
  22. v.Field(0).SetFloat(0.4)
  23. v.Field(1).SetInt(2)
  24. s := v.Addr().Interface()
  25. w := new(bytes.Buffer)
  26. if err := json.NewEncoder(w).Encode(s); err != nil {
  27. panic(err)
  28. }
  29. fmt.Printf("value: %+v\n", s)
  30. fmt.Printf("json: %s", w.Bytes())
  31. r := bytes.NewReader([]byte(`{"height":1.5,"age":10}`))
  32. if err := json.NewDecoder(r).Decode(s); err != nil {
  33. panic(err)
  34. }
  35. fmt.Printf("value: %+v\n", s)
  36. }

type Value

Value为go值提供了反射接口。
不是所有go类型值的Value表示都能使用所有方法。请参见每个方法的文档获取使用限制。在调用有分类限定的方法时,应先使用Kind方法获知该值的分类。调用该分类不支持的方法会导致运行时的panic。

初始化

func ValueOf(i interface{}) Value

  • ValueOf返回一个初始化为i接口保管的具体值的Value,ValueOf(nil)返回Value零值。

func NewAt(typ Type, p unsafe.Pointer) Value

  • NewAt返回一个Value类型值,该值持有一个指向类型为typ、地址为p的值的指针。

func New(typ Type) Value

  • New返回一个Value类型值,该值持有一个指向类型为typ的新申请的零值的指针,返回值的Type为PtrTo(typ)。

func Indirect(v Value) Value

  • 返回持有v持有的指针指向的值的Value。如果v持有nil指针,会返回Value零值;如果v不持有指针,会返回v。

func (v Value) IsValid() bool

  • IsValid返回v是否持有一个值。如果v是Value零值会返回假

func (v Value) IsNil() bool

  • IsNil报告v持有的值是否为nil。v持有的值的分类必须是通道、函数、接口、映射、指针、切片之一;否则IsNil函数会导致panic。
  • 该方法可判断interface的值是否为nil(比如interface的type不为nil,但值为nil)

func (v Value) IsZero() bool IsZero报告v是否为其类型的零值。如果v无效,它就会恐慌

func (v Value) Kind() Kind

  • Kind返回v持有的值的分类,如果v是Value零值,返回值为Invalid

func (v Value) Type() Type

  • 返回v持有的值的类型的Type表示。

func (v Value) Convert(t Type) Value

  • Convert将v持有的值转换为类型为t的值,并返回该值的Value封装。如果go转换规则不支持这种转换,会panic。

func (v Value) Elem() Value

  • Elem返回接口v包含的值或指针v指向的值。如果v的Kind不是Interface或Ptr会panic;如果v持有的值为nil,会返回Value零值。
  • Elem用来获取原始值对应的反射对象
  • 原则:如果要修改反射类型对象,其值必须是“addressable” ```go type AAA struct { }

func main() { a1 := AAA{} a2 := &AAA{} test1(a1) test2(a2) }

func test1(v interface{}) { fmt.Println(reflect.ValueOf(v).Kind()) // struct fmt.Println(reflect.ValueOf(v).CanAddr()) // false,这个操作是无意义的 fmt.Println(reflect.ValueOf(v).Elem().Kind()) // panic }

func test2(v interface{}) { fmt.Println(reflect.ValueOf(v).Kind()) // ptr fmt.Println(reflect.ValueOf(v).Elem().Kind()) // struct fmt.Println(reflect.ValueOf(v).CanAddr()) // false,这个操作是无意义的 fmt.Println(reflect.ValueOf(v).Elem().CanAddr()) // true }

  1. func (v [Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value)) CanAddr() [bool](https://studygolang.com/static/pkgdoc/pkg/builtin.htm#bool)
  2. - 返回是否可以获取v的指针
  3. - 正确姿势:reflect.ValueOf(i).Elem().Addr()
  4. - 不可能直接 reflect.ValueOf(i).Addr()
  5. func (v [Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value)) Addr() [Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value)
  6. - 返回一个持有指向v的指针的Value封装。如果v.CanAddr()返回假,调用本方法会panic
  7. - Addr一般用于获取结构体字段的指针或者切片的元素(的Value封装)以便调用需要指针类型接收者的方法
  8. func (v [Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value)) CanInterface() [bool](https://studygolang.com/static/pkgdoc/pkg/builtin.htm#bool) 判断v能否转为Interface
  9. func (v [Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value)) Interface() (i interface{}) 本方法返回v当前持有的值(表示为/保管在interface{}类型)
  10. <a name="VpBdD"></a>
  11. #### 切片,管道,map
  12. func (v [Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value)) Cap() [int](https://studygolang.com/static/pkgdoc/pkg/builtin.htm#int)
  13. - 返回v持有值的容量,如果vKind不是ArrayChanSlicepanic
  14. func (v [Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value)) Len() [int](https://studygolang.com/static/pkgdoc/pkg/builtin.htm#int)
  15. - 返回v持有值的长度,如果vKind不是ArrayChanSliceMapStringpanic
  16. func (v [Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value)) Slice(i, j [int](https://studygolang.com/static/pkgdoc/pkg/builtin.htm#int)) [Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value)
  17. - 返回v[i:j](v持有的切片的子切片的Value封装);如果vKind不是ArraySliceStringpanic。如果v是一个不可寻址的数组,或者索引出界,也会panic
  18. func (v [Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value)) Slice3(i, j, k [int](https://studygolang.com/static/pkgdoc/pkg/builtin.htm#int)) [Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value)
  19. - Slice3参数版本,返回v[i:j:k]
  20. func (v [Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value)) Index(i [int](https://studygolang.com/static/pkgdoc/pkg/builtin.htm#int)) [Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value)
  21. - 返回v持有值的第i个元素。如果vKind不是ArrayChanSliceString,或者i出界,会panic
  22. func (v [Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value)) SetCap(n [int](https://studygolang.com/static/pkgdoc/pkg/builtin.htm#int))
  23. - 设定v持有值的容量。如果vKind不是Slice或者n出界(小于长度或超出容量),将导致panic
  24. func (v [Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value)) SetLen(n [int](https://studygolang.com/static/pkgdoc/pkg/builtin.htm#int))
  25. - 设定v持有值的长度。如果vKind不是Slice或者n出界(小于零或超出容量),将导致panic
  26. func (v [Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value)) SetMapIndex(key, val [Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value))
  27. - 用来给v的映射类型持有值添加/修改键值对,如果valValue零值,则是删除键值对。如果vKind不是Map,或者v的持有值是nil,将会panickey的持有值必须可以直接赋值给v持有值类型的键类型。val的持有值必须可以直接赋值给v持有值类型的值类型
  28. <a name="rpPTb"></a>
  29. ####
  30. <a name="e2wp1"></a>
  31. #### 切片
  32. func MakeSlice(typ [Type](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Type), len, cap [int](https://studygolang.com/static/pkgdoc/pkg/builtin.htm#int)) [Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value)
  33. - MakeSlice创建一个新申请的元素类型为typ,长度len容量cap的切片类型的Value值。
  34. func Append(s [Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value), x ...[Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value)) [Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value)
  35. - 向切片类型的Values中添加一系列值,xValue值持有的值必须能直接赋值给s持有的切片的元素类型。
  36. func AppendSlice(s, t [Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value)) [Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value)
  37. - 类似Append函数,但接受一个切片类型的Value值。将切片t的每一个值添加到s
  38. <a name="cu92P"></a>
  39. #### map
  40. func MakeMap(typ [Type](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Type)) [Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value) MakeMap创建一个特定映射类型的Value值。
  41. func (v [Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value)) MapIndex(key [Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value)) [Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value)
  42. - 返回v持有值里key持有值为键对应的值的Value封装。如果vKind不是Mappanic
  43. func (v [Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value)) MapKeys() [][Value](https://studygolang.com/static/pkgdoc/pkg/reflect.htm#Value)
  44. - 返回一个包含v持有值中所有键的Value封装的切片,该切片未排序。如果vKind不是Mappanic。如果v持有值是nil,返回空切片(非nil)。
  45. func (v [Value](https://golang.org/pkg/reflect/#Value)) MapRange() *[MapIter](https://golang.org/pkg/reflect/#MapIter) 返回一个范围迭代器。如果v的类型不是Map,它就会恐慌。
  46. ```go
  47. iter := reflect.ValueOf(m).MapRange()
  48. for iter.Next() {
  49. k := iter.Key()
  50. v := iter.Value()
  51. ...
  52. }

管道

func MakeChan(typ Type, buffer int) Value

  • MakeChan创建一个元素类型为typ、有buffer个缓存的通道类型的Value值。

func (v Value) Recv() (x Value, ok bool)

  • 方法从v持有的通道接收并返回一个值(的Value封装)。如果v的Kind不是Chan会panic。方法会阻塞直到获取到值。如果返回值x对应于某个发送到v持有的通道的值,ok为真;如果因为通道关闭而返回,x为Value零值而ok为假。

func (v Value) TryRecv() (x Value, ok bool)

  • TryRecv尝试从v持有的通道接收一个值,但不会阻塞。如果v的Kind不是Chan会panic。如果方法成功接收到一个值,会返回该值(的Value封装)和true;如果不能无阻塞的接收到值,返回Value零值和false;如果因为通道关闭而返回,返回值x是持有通道元素类型的零值的Value和false。

func (v Value) Send(x Value)

  • 方法向v持有的通道发送x持有的值。如果v的Kind不是Chan,或者x的持有值不能直接赋值给v持有通道的元素类型,会panic

func (v Value) TrySend(x Value) bool

  • TrySend尝试向v持有的通道发送x持有的值,但不会阻塞。如果v的Kind不是Chan会panic。如果成功发送会返回真,否则返回假。x的持有值必须可以直接赋值给v持有通道的元素类型。

func (v Value) Close() 关闭v持有的通道,如果v的Kind不是Chan会panic

值类型判断

func (v Value) Bool() bool

  • 返回v持有的布尔值,如果v的Kind不是Bool会panic

func (v Value) Int() int64

  • 返回v持有的有符号整数(表示为int64),如果v的Kind不是Int、Int8、Int16、Int32、Int64会panic

func (v Value) OverflowInt(x int64) bool

  • 如果v持有值的类型不能无溢出的表示x,会返回真。如果v的Kind不是Int、Int8、Int16、Int32、Int64会panic

func (v Value) Uint() uint64

  • 返回v持有的无符号整数(表示为uint64),如v的Kind不是Uint、Uintptr、Uint8、Uint16、Uint32、Uint64会panic

func (v Value) OverflowUint(x uint64) bool

  • 如果v持有值的类型不能无溢出的表示x,会返回真。如果v的Kind不是Uint、Uintptr、Uint8、Uint16、Uint32、Uint64会panic

func (v Value) Float() float64

  • 返回v持有的浮点数(表示为float64),如果v的Kind不是Float32、Float64会panic

func (v Value) OverflowFloat(x float64) bool

  • 如果v持有值的类型不能无溢出的表示x,会返回真。如果v的Kind不是Float32、Float64会panic

func (v Value) Complex() complex128

  • 返回v持有的复数(表示为complex64),如果v的Kind不是Complex64、Complex128会panic

func (v Value) OverflowComplex(x complex128) bool

  • 如果v持有值的类型不能无溢出的表示x,会返回真。如果v的Kind不是Complex64、Complex128会panic

func (v Value) Bytes() []byte

  • 返回v持有的[]byte类型值。如果v持有的值的类型不是[]byte会panic

func (v Value) String() string

  • 返回v持有的值的字符串表示

func (v Value) Interface() (i interface{})

  • 本方法返回v当前持有的值(表示为/保管在interface{}类型)

func (v Value) InterfaceData() [2]uintptr

  • 返回v持有的接口类型值的数据。如果v的Kind不是Interface会panic

字段

func (v Value) NumField() int

  • 返回v持有的结构体类型值的字段数,如果v的Kind不是Struct会panic

func (v Value) Field(i int) Value

  • 返回结构体的第i个字段(的Value封装)。如果v的Kind不是Struct或i出界会panic

func (v Value) FieldByIndex(index []int) Value

  • 返回索引序列指定的嵌套字段的Value表示,等价于用索引中的值链式调用本方法,如v的Kind非Struct将会panic

func (v Value) FieldByName(name string) Value

  • 返回该类型名为name的字段(的Value封装)(会查找匿名字段及其子字段),如果v的Kind不是Struct会panic;如果未找到会返回Value零值。

func (v Value) FieldByNameFunc(match func(string) bool) Value

  • 返回该类型第一个字段名满足match的字段(的Value封装)(会查找匿名字段及其子字段),如果v的Kind不是Struct会panic;如果未找到会返回Value零值。

方法

func (v Value) Call(in []Value) []Value

  • Call方法使用输入的参数in调用v持有的函数。例如,如果len(in) == 3,v.Call(in)代表调用v(in[0], in[1], in[2])(其中Value值表示其持有值)。如果v的Kind不是Func会panic。

func (v Value) Method(i int) Value

  • 返回v持有值类型的第i个方法,按方法名的ASCII码排序,越界会panic

func (v Value) MethodByName(name string) Value

func (v Value) NumMethod() int 返回v持有值的方法集的方法数目

赋值

func (v Value) CanSet() bool 如果v持有的值可以被修改

func (v Value) SetBool(x bool) 设置v的持有值。如果v的Kind不是Bool或者v.CanSet()返回假,会panic。

func (v Value) SetInt(x int64)

  • 设置v的持有值。如果v的Kind不是Int、Int8、Int16、Int32、Int64之一或者v.CanSet()返回假,会panic

func (v Value) SetUint(x uint64)

  • 设置v的持有值。如果v的Kind不是Uint、Uintptr、Uint8、Uint16、Uint32、Uint64或者v.CanSet()返回假,会panic。

func (v Value) SetFloat(x float64)

  • 设置v的持有值。如果v的Kind不是Float32、Float64或者v.CanSet()返回假,会panic。

func (v Value) SetComplex(x complex128)

  • 设置v的持有值。如果v的Kind不是Complex64、Complex128或者v.CanSet()返回假,会panic。

func (v Value) SetBytes(x []byte)

  • 设置v的持有值。如果v持有值不是[]byte类型或者v.CanSet()返回假,会panic。

func (v Value) SetString(x string)

  • 设置v的持有值。如果v的Kind不是String或者v.CanSet()返回假,会panic。

func (v Value) SetPointer(x unsafe.Pointer)

  • 设置v的持有值。如果v的Kind不是UnsafePointer或者v.CanSet()返回假,会panic

func (v Value) Set(x Value)

  • 将v的持有值修改为x的持有值。如果v.CanSet()返回假,会panic。x的持有值必须能直接赋给v持有值的类型。

拷贝与判断

func Copy(dst, src Value) int

  • 将src中的值拷贝到dst,直到src被耗尽或者dst被装满,要求这二者都是slice或array,且元素类型相同。

func DeepEqual(a1, a2 interface{}) bool

  • 用来判断两个值是否深度一致:除了类型相同;在可以时(主要是基本类型)会使用==;但还会比较array、slice的成员,map的键值对,结构体字段进行深入比对。map的键值对,对键只使用==,但值会继续往深层比对。DeepEqual函数可以正确处理循环的类型。函数类型只有都会nil时才相等;空切片不等于nil切片;还会考虑array、slice的长度、map键值对数。

type SliceHeader

SliceHeader是slice类型的运行时表示

  1. type SliceHeader struct {
  2. Data uintptr
  3. Len int
  4. Cap int
  5. }

type StringHeader

StringHeader是切片的运行时表示

  1. type StringHeader struct {
  2. Data uintptr
  3. Len int
  4. }

学习记录

ConvertibleTo

如该类型的值可以转换为u代表的类型,返回真,什么情况下返回是可以转换的?对于结构体有三个条件

  • 字段类型一样
  • 字段名一样
  • 字段顺序一样

对于字段ConvertibleTo,就是类型可以相互转换,例如 int32 转为 int64
可以ConvertibleTo

  1. type person struct {
  2. Name string
  3. Role string
  4. Age int32
  5. }
  6. type person2 struct {
  7. Name string
  8. Role string
  9. Age int32
  10. }
  11. func main() {
  12. var p person
  13. var p2 person2
  14. pt := reflect.TypeOf(p)
  15. pt2 := reflect.TypeOf(p)
  16. fmt.Println(pt.ConvertibleTo(pt2)) // true
  17. }

不可以ConvertibleTo

  • 字段不一样 ```go type person struct { Name string Role string Age int32 }

type person2 struct { Name string Role string }

  1. - 字段顺序不一样
  2. ```go
  3. type person struct {
  4. Name string
  5. Role string
  6. Age int32
  7. }
  8. type person2 struct {
  9. Name string
  10. Age int32
  11. Role string
  12. }
  • 字段类型不一样 ```go type person struct { Name string Role string Age int32 }

type person2 struct { Name string Role string Age int64 }

  1. **类型转换**
  2. ```go
  3. type person struct {
  4. Name string
  5. Role string
  6. Age int32
  7. }
  8. type person2 struct {
  9. Name string
  10. Role string
  11. Age int32
  12. }
  13. func main() {
  14. var p = person{"1", "2", 3}
  15. var p2 person2
  16. from := reflect.ValueOf(&p).Elem()
  17. to := reflect.ValueOf(&p2).Elem()
  18. if to.CanSet() && from.Type().ConvertibleTo(to.Type()) {
  19. tmp := from.Convert(to.Type())
  20. // 这步判断可以忽略,因为from.Convert(to.Type()),to与tmp的type肯定是一样的
  21. if to.Type().AssignableTo(tmp.Type()) {
  22. to.Set(tmp)
  23. }
  24. }
  25. fmt.Println(p2)
  26. }

AssignableTo

如果该类型的值可以直接赋值给u代表的类型,返回真。什么叫可以直接赋值?即类型一样

  1. type person struct {
  2. Name string
  3. Role string
  4. Age int32
  5. }
  6. type person2 struct {
  7. Name string
  8. Role string
  9. Age int32
  10. }
  11. func main() {
  12. var p person
  13. var p2 person2
  14. var p3 person
  15. from := reflect.ValueOf(&p).Elem()
  16. to := reflect.ValueOf(&p2).Elem()
  17. to2 := reflect.ValueOf(&p3).Elem()
  18. fmt.Println(from.Type().AssignableTo(to.Type())) // false
  19. fmt.Println(from.Type().AssignableTo(to2.Type())) // true
  20. }

Addr

type person2 struct {
    Name *string
    Role string
    Age  int32
}

func main() {

    var p2 person2

    fmt.Println(reflect.ValueOf(&p2).Elem().FieldByName("Name").Addr().Type()) //  **string
    fmt.Println(reflect.ValueOf(&p2).Elem().FieldByName("Role").Addr().Type()) //  *string
    fmt.Println(reflect.ValueOf(&p2).Elem().FieldByName("Age").Addr().Type())  //  *int32
}
type person2 struct {
    Name *string
    Role string
    Age  int32
}

func main() {

    var p2 = person2{nil, "管理员", 22}

    fmt.Println(reflect.ValueOf(&p2).Elem().FieldByName("Name").Addr().Elem()) //  <nil>
    fmt.Println(reflect.ValueOf(&p2).Elem().FieldByName("Role").Addr().Elem()) //  管理员
    fmt.Println(reflect.ValueOf(&p2).Elem().FieldByName("Age").Addr().Elem())  //  22

    fmt.Println(reflect.ValueOf(&p2).Elem().FieldByName("Name").Addr()) //  0xc0000044a0
    fmt.Println(reflect.ValueOf(&p2).Elem().FieldByName("Role").Addr()) //  0xc0000044a8
    fmt.Println(reflect.ValueOf(&p2).Elem().FieldByName("Age").Addr())  //  0xc0000044b8
}
func main() {
    list := []int64{1, 2, 3}

    fmt.Printf("%+v\n", reflect.ValueOf(&list).Elem().Addr())        // &[1 2 3]
    fmt.Printf("%+v\n", reflect.ValueOf(&list).Elem().Addr().Type()) // *[]int64
    fmt.Printf("%+v\n", reflect.ValueOf(&list).Elem().Addr().Elem()) // [1 2 3]
}

Comparable

https://golang.org/ref/spec#Comparison_operators
Golang 中有很多时候要用到comparable types,例如比较struct的时候,例如map里的 key。弄清楚有哪些类型是comparable的非常重要。
比较操作符比较两个操作数并产生一个无类型布尔值

==    equal
!=    not equal
<     less
<=    less or equal
>     greater
>=    greater or equal

在任何比较中,第一个操作数必须可赋值(AssignableTo)给第二个操作数的类型,反之亦然。
可比较的类型:

  • Boolean
  • Integer
  • Floating-point
  • Complex
  • String
  • Pointer , 如果两个指针指向同一个变量,或者值都为nil,那么它们的值是相等的。指向不同的零大小变量(struct)的指针可能相等,也可能不相等
  • Channel , 如果两个通道值是由同一个调用创建的,或者它们的值都为nil,那么它们是相等的
  • Interface , 如果它们有相同的动态类型和相等的动态值,或者两者都为nil,那么它们是相等的
  • Struct,如果它们的所有字段都是可比较的,那么结构体具有可比性。如果两个结构值对应的非空白字段相等,则两个结构值相等。
  • Array(注意不是Slice),如果数组元素类型的值具有可比性,那么数组值也具有可比性。如果两个数组对应的元素相等,则两个数组值相等

即不可以比较的类型有:func、slice、map