Go reflect包中Type接口函数全解析

Align / FieldAlign

函数描述:

  • Align:获取变量在内存中的对的字节齐值(通用)
  • FieldAlign:获取Struct在内存中的字节对齐值(针对结构体)

关于Go的内存对齐可以参考:https://studygolang.com/articles/19663

使用示例:

func HelloWorld() string {
	return "hello world"
}

type St struct {
	a int64
	b int8
	c string
	d float64
	e func()
}

func main() {
	a := St{}
	b := int8(10)
	c := "hello world"
	fmt.Println(reflect.TypeOf(a).Align()) // 8
    fmt.Println(reflect.TypeOf(a).FieldAlign()) // 8
	fmt.Println(reflect.TypeOf(b).Align()) // 1
	fmt.Println(reflect.TypeOf(c).Align()) // 8
	fmt.Println(reflect.TypeOf(HelloWorld).Align()) // 8
}

哈哈, 问个问题,以下输出结果是什么?

fmt.Println(unsafe.Sizeof(a))

NumMethod / Method / MethodByName

函数描述:

  • NumMethod:返回可导出的方法数量
  • Method:通过index获取方法信息,此处方法是按字典顺序顺序排序,与方法位置先后无关
  • MethodByName:通过方法名获取方法信息

使用示例:

type Student struct {
	Id int64
	Name string
	Agent int8
}

func (s Student) Run() {
	fmt.Println("run....")
}

func (s Student) Learn() {
	fmt.Println("learns....")
}

func(s Student) cray() {
	fmt.Println("cry...")
}

func (s *Student) Jump() {
	fmt.Println("jump....")
}

func(s *Student) Speak() {
	fmt.Println("speak....")
}
func(s *Student) sad () {
	fmt.Println("sad...")
}

func main() {
	a := Student{}
	b := &Student{}

	aType := reflect.TypeOf(a)
	bType := reflect.TypeOf(b)

	fmt.Println(aType.NumMethod())
	fmt.Println(bType.NumMethod())
	for i :=0; i < aType.NumMethod(); i++ {
		name := aType.Method(i).Name
		fmt.Println(name)
		fmt.Println(aType.MethodByName(name))
	}

	for i :=0; i < bType.NumMethod(); i++ {
		name := bType.Method(i).Name
		fmt.Println(name)
		fmt.Println(bType.MethodByName(name))
	}

	if m,ok :=  aType.MethodByName("sad"); ok {
		fmt.Println(m.Name)
	}

	if m,ok :=  bType.MethodByName("Speak"); ok {
		fmt.Println(m.Name)
	}

	if m,ok :=  bType.MethodByName("Speak"); ok {
		fmt.Println(m.Name)
	}
}

Name / String / Size / PkgPath

函数描述:

  • Name:返回类型名称(包内部的名称,不包含包名)
  • String:返回类型的字符串表示,此处会使用短包名,如: 会用 base64 代替 encoding/base64,不保证唯一性
  • PkgPath:返回变量所在包路径
  • Size:返回类型所需存储空间大小,类似于unsafe.Sizeof

使用示例:

func main() {
	c := base64.Encoding{}
	cType := reflect.TypeOf(c)

	fmt.Println(cType.Name()) // Encoding
	fmt.Println(cType.String()) // base64.Encoding
	fmt.Println(cType.PkgPath()) // encoding/base64
	fmt.Println(cType.Size()) // 328
}

Kind / Implements / AssignableTo / ConvertibleTo / Comparable

函数描述:

  • Kind:返回变量类型的分类
  • Implements:检测变量是否实现了参数指定的接口,参数必须为interface类型
  • AssignableTo:检测变量值是否可以赋值给参数指定的类型
  • ConvertibleTo:变量类型值是否可以转换成参数指定的类型的值
  • Comparable:变量的类型值是否可比较

Go语言中所有类型如下:

Invalid
Bool
Int
Int8
Int16
Int32
Int64
Uint
Uint8
Uint16
Uint32
Uint64
Uintptr
Float32
Float64
Complex64
Complex128
Array
Chan
Func
Interface
Map
Ptr
Slice
String
Struct
UnsafePointer

使用示例:

type Human interface {
	Run()
	Learn()
	Jump()
}

type Student struct {
	Id    int64
	Name  string
	Agent int8
}

func (s Student) Run() {
	fmt.Println("run....")
}

func (s Student) Learn() {
	fmt.Println("learns....")
}

func (s Student) cray() {
	fmt.Println("cry...")
}

func (s *Student) Jump() {
	fmt.Println("jump....")
}

func (s *Student) Speak() {
	fmt.Println("speak....")
}
func (s *Student) sad() {
	fmt.Println("sad...")
}

func main() {
	a := Student{}
	b := &Student{}
	var c *Human

	aType := reflect.TypeOf(a)
	bType := reflect.TypeOf(b)
	cType := reflect.TypeOf(c).Elem()

	fmt.Println(aType.Kind().String()) // Struct
	fmt.Println(bType.Kind().String()) // ptr
	fmt.Println(cType.Kind().String()) // interface

	fmt.Println(aType.Implements(cType)) // false
	fmt.Println(bType.Implements(cType)) // true
	fmt.Println(bType.AssignableTo(aType)) // false
	fmt.Println(bType.AssignableTo(cType)) // true
	fmt.Println(bType.ConvertibleTo(aType)) // false
	fmt.Println(bType.ConvertibleTo(cType)) // true
	fmt.Println(bType.Comparable()) // true
}

上面提到的方法都是都是和类型无关的,所有类型都可以调用,而下面的方法是和类型相关的,只有部分类型可以调用

Elem

方法描述:方法返回类型所对应的元素的类型

  • 对于Map类型,返回字典值的类型。
  • 对于指针类型Ptr,它返回指针指向的元素的类型。
  • 对于Chan,它返回传递的元素的类型。
  • 数组和Slice返回的是它包含的元素的类型。

支持类型:Array, Chan, Map, Ptr, Slice

使用示例:

func main() {
	a := int8(8)
	b := map[string]int64{}
	c := make(chan int32)
	fmt.Println(reflect.TypeOf(&a).Elem().Name()) // int8
	fmt.Println(reflect.TypeOf(b).Elem().Name()) // int64
	fmt.Println(reflect.TypeOf(c).Elem().Name()) // int32
}

Bits

方法描述:返回类型所占位大小

支持的类型:Int*, Uint*, Float*, Complex*

使用示例:

func main() {
	a := int8(10)
	b := float32(30)
	c := float64(30)
	aType := reflect.TypeOf(&a)
	bType := reflect.TypeOf(&b)
	cType := reflect.TypeOf(&c)
	fmt.Println(aType.Elem().Bits()) // 8
	fmt.Println(bType.Elem().Bits()) // 32
	fmt.Println(cType.Elem().Bits()) // 64
    fmt.Println(dType.Elem().Bits()) // panic
}

ChanDir

方法描述:返回channel的方向

支持的类型:chan

用法示例:

func main() {
	a := make(chan<- int)
	b := make(<-chan int)
	c := make(chan int)
	aType := reflect.TypeOf(a)
	bType := reflect.TypeOf(b)
	cType := reflect.TypeOf(c)
	fmt.Println(aType.ChanDir()) // chan <-
	fmt.Println(bType.ChanDir()) // <- chan
	fmt.Println(cType.ChanDir()) // chan
}

In / NumIn / Out / NumOut / IsVariadic

方法描述:

  • NumIn:返回方法参数个数
  • In:返回方法第 i 个参数的类型,i 的范围是 [0, NumIn() - 1]
  • NumOut:返回方法返回值个数
  • Out:返回方法第 i 个 返回值的类型,i 的范围为 [0, NumOut() - 1]
  • IsVariadic:判断方法是否存在可变参数

支持类型:Func

使用示例:

func Hello(a, b, c string, d... int) (string, string, []int) {
	rtu := fmt.Sprintf("Hello %s %s %s %d", a, b, c, d)
	fmt.Println(rtu)
	return a, b + c, d
}

func Hello2(a, b, c string, d []int) (string, string, []int) {
	rtu := fmt.Sprintf("Hello %s %s %s %d", a, b, c, d)
	fmt.Println(rtu)
	return a, b + c, d
}

func HelloWorld() {
	fmt.Println("Hello World")
}

func main() {
	aType := reflect.TypeOf(Hello)
	bType := reflect.TypeOf(HelloWorld)
	cType := reflect.TypeOf(Hello2)

	fmt.Println(aType.NumIn())
	for i := 0; i < aType.NumIn(); i++ {
		fmt.Println(aType.In(i))
	}

	fmt.Println(aType.NumOut())
	for i:=0; i< aType.NumOut(); i++ {
		fmt.Println(aType.Out(i))
	}

	fmt.Println(aType.IsVariadic()) // true
	fmt.Println(bType.IsVariadic()) // false
	fmt.Println(cType.IsVariadic()) // false

}

Key

方法描述:返回Map key 的类型

支持类型:Map

使用示例:

func main() {
	a := make(map[string]int)
	b := make(map[int32]string)
	fmt.Println(reflect.TypeOf(a).Key())
	fmt.Println(reflect.TypeOf(b).Key())
}

Field / FieldByIndex / FieldByName / FieldByNameFunc / NumField

方法描述:

  • Field:获取第 i 个字段的信息,i范围为[0, NumField-1],匿名字段不会自动展开,只认为是一个字段
  • NumField:获取结构体字段总数,匿名字段只认为是一个字段
  • FieldByIndex:通过 i 获取第 i 个字段信息,支持对结构体嵌套的查找
  • FieldByNameFunc:通过传入match方法,来实现对属性的获取,当有且只匹配一次的时候,才正常返回,支持对匿名字段及其字段查找
  • FieldByName:通过属性名对结构体字段进行查找

支持类型:Struct

使用示例:

type A struct {
	a int
	ab int32
	b string
	c float64
}

type B struct {
	c A
	d int
	f int8
}

type C struct {
	d int
	f int8
	A
}

func main() {
	a := A{}
	b := B{}
	c := C{}
	aType := reflect.TypeOf(a)
	bType := reflect.TypeOf(b)
	cType := reflect.TypeOf(c)

	fmt.Println(aType.NumField())
	for i := 0; i < aType.NumField();i++ {
		fmt.Println(aType.Field(i))
	}
	fmt.Println(bType.NumField())
	for i := 0; i < bType.NumField();i++ {
		fmt.Println(bType.Field(i))
	}

	fmt.Println(cType.NumField())
	for i := 0; i < cType.NumField();i++ {
		fmt.Println(cType.Field(i))
	}

	fmt.Println(aType.FieldByIndex([]int{0})) // {a main int  0 [0] false}
	fmt.Println(bType.FieldByIndex([]int{0, 2})) // {b main string  16 [2] false}

	fmt.Println(aType.FieldByName("a")) // {a main int  0 [0] false} true
	fmt.Println(bType.FieldByName("c.a")) // {  <nil>  0 [] false} false

	fmt.Println(bType.FieldByNameFunc(func(s string) bool {
		return strings.HasPrefix(s, "ab")
	})) // {  <nil>  0 [] false} false

	fmt.Println(cType.FieldByNameFunc(func(s string) bool {
		return strings.HasPrefix(s, "ab")
	})) // {ab main int32  8 [2 1] false} true

	fmt.Println(cType.FieldByNameFunc(func(s string) bool {
		return strings.HasPrefix(s, "a")
	})) // {  <nil>  0 [] false} false
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章