Тип reflect.Type

Тип reflect.Type представляет собой интерфейс, который содержит информацию о типе данных во время выполнения программы. Он позволяет получать различные сведения о типе: его имя, пакет, размер, структуру полей и методов. Основным способом получения значения reflect.Type является вызов функции reflect.TypeOf, которая возвращает тип переданного значения. Этот интерфейс предоставляет множество методов для анализа и работы с типами данных в рефлексии.

Получение типа значения

Для получения типа переменной используется функция reflect.TypeOf, которая возвращает значение интерфейса reflect.Type. Если передать nil, функция вернет nil.

gopackage main

import (
  "fmt"
  "reflect"
)

func main() {
  var num int = 42
  var str string = "hello"
  var arr [3]int

  typeOfNum := reflect.TypeOf(num)
  typeOfStr := reflect.TypeOf(str)
  typeOfArr := reflect.TypeOf(arr)

  fmt.Println(typeOfNum)
  fmt.Println(typeOfStr)
  fmt.Println(typeOfArr)
}

Результат выполнения кода:

go"int"
"string"
"[3]int"

Получение имени и пути пакета

Методы Name и PkgPath позволяют получить имя типа и путь пакета, в котором он объявлен. Для встроенных типов имя возвращается, а путь пакета будет пустой строкой.

gopackage main

import (
  "fmt"
  "reflect"
)

type User struct {
  Name string
  Age  int
}

func main() {
  var u User
  t := reflect.TypeOf(u)

  fmt.Println(t.Name())
  fmt.Println(t.PkgPath())

  var num int
  tInt := reflect.TypeOf(num)
  fmt.Println(tInt.Name())
  fmt.Println(tInt.PkgPath())
}

Результат выполнения кода:

go"User"
"main"
"int"
""

Получение строкового представления

Метод String возвращает строковое представление типа, которое может использоваться для вывода или сравнения. Это представление соответствует синтаксису объявления типа в Go.

gopackage main

import (
  "fmt"
  "reflect"
)

func main() {
  var slice []int
  var m map[string]int
  var fn func(int) string

  fmt.Println(reflect.TypeOf(slice).String())
  fmt.Println(reflect.TypeOf(m).String())
  fmt.Println(reflect.TypeOf(fn).String())
}

Результат выполнения кода:

go"[]int"
"map[string]int"
"func(int) string"

Проверка реализации интерфейса

Метод Implements позволяет проверить, реализует ли тип заданный интерфейс. Для этого необходимо передать reflect.Type интерфейса, который нужно проверить.

gopackage main

import (
  "fmt"
  "reflect"
)

type Stringer interface {
  String() string
}

type MyInt int

func (m MyInt) String() string {
  return fmt.Sprintf("%d", m)
}

func main() {
  var i MyInt
  t := reflect.TypeOf(i)
  interfaceType := reflect.TypeOf((*Stringer)(nil)).Elem()

  fmt.Println(t.Implements(interfaceType))

  var num int
  tInt := reflect.TypeOf(num)
  fmt.Println(tInt.Implements(interfaceType))
}

Результат выполнения кода:

go"true"
"false"

Получение информации о структуре

Методы NumField и Field позволяют получить информацию о полях структуры. Метод NumField возвращает количество полей, а Field по индексу возвращает объект reflect.StructField с информацией о поле.

gopackage main

import (
  "fmt"
  "reflect"
)

type Person struct {
  Name  string
  Age   int
  Address string
}

func main() {
  p := Person{"John", 30, "123 Main St"}
  t := reflect.TypeOf(p)

  fmt.Println(t.NumField())

  for i := 0; i < t.NumField(); i++ {
    field := t.Field(i)
    fmt.Printf("%s: %s\n", field.Name, field.Type)
  }
}

Результат выполнения кода:

go"3"
"Name: string"
"Age: int"
"Address: string"

Получение информации о методах

Методы NumMethod и Method позволяют получить информацию о методах типа. Метод NumMethod возвращает количество методов, а Method по индексу возвращает объект reflect.Method с информацией о методе.

gopackage main

import (
  "fmt"
  "reflect"
)

type Calculator struct{}

func (c Calculator) Add(a, b int) int {
  return a + b
}

func (c Calculator) Sub(a, b int) int {
  return a - b
}

func main() {
  var calc Calculator
  t := reflect.TypeOf(calc)

  fmt.Println(t.NumMethod())

  for i := 0; i < t.NumMethod(); i++ {
    method := t.Method(i)
    fmt.Printf("%s: %v\n", method.Name, method.Type)
  }
}

Результат выполнения кода:

go"2"
"Add: func(main.Calculator, int, int) int"
"Sub: func(main.Calculator, int, int) int"

Получение элемента составного типа

Метод Elem возвращает тип элемента для составных типов: указателей, массивов, срезов, каналов и карт. Это позволяет получить информацию о типе, на который указывает указатель, или о типе элементов среза.

gopackage main

import (
  "fmt"
  "reflect"
)

func main() {
  var ptr *int
  var slice []string
  var arr [5]bool

  tPtr := reflect.TypeOf(ptr)
  tSlice := reflect.TypeOf(slice)
  tArr := reflect.TypeOf(arr)

  fmt.Println(tPtr.Elem())
  fmt.Println(tSlice.Elem())
  fmt.Println(tArr.Elem())
}

Результат выполнения кода:

go"int"
"string"
"bool"

Проверка совместимости типов

Метод AssignableTo проверяет, можно ли присвоить значение одного типа переменной другого типа. Метод ConvertibleTo проверяет, можно ли преобразовать значение одного типа к другому.

gopackage main

import (
  "fmt"
  "reflect"
)

type MyInt int

func main() {
  var i int
  var mi MyInt
  var f float64

  tInt := reflect.TypeOf(i)
  tMyInt := reflect.TypeOf(mi)
  tFloat := reflect.TypeOf(f)

  fmt.Println(tInt.AssignableTo(tMyInt))
  fmt.Println(tInt.ConvertibleTo(tMyInt))
  fmt.Println(tInt.ConvertibleTo(tFloat))
}

Результат выполнения кода:

go"false"
"true"
"true"

Смотрите также

  • функцию reflect.TypeOf,
    которая возвращает тип значения
  • тип reflect.Value,
    который представляет значение во время выполнения
  • метод reflect.Type.Kind,
    который возвращает базовый вид типа
  • структуру reflect.StructField,
    которая содержит информацию о поле структуры