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
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章