Метод reflect.Type.Method

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

Синтаксис

gotype Type interface {
  Method(i int) Method
}

Структура reflect.Method

gotype Method struct {
  Name  string
  PkgPath string
  Type  Type
  Func  Value
  Index   int
}

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

Давайте получим информацию о первом методе пользовательского типа:

gopackage main

import (
  "fmt"
  "reflect"
)

type User struct {
  Name string
  Age  int
}

func (u User) GetName() string {
  return u.Name
}

func (u User) GetAge() int {
  return u.Age
}

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

  method := t.Method(0)
  fmt.Println("Method name:", method.Name)
  fmt.Println("Method index:", method.Index)
  fmt.Println("Method type:", method.Type)
}

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

go"Method name: GetAge"
"Method index: 0"
"Method type: func(main.User) int"

Пример вызова метода с помощью Value

Давайте вызовем полученный метод с использованием reflect.Value:

gopackage main

import (
  "fmt"
  "reflect"
)

type Calculator struct {
  Value int
}

func (c Calculator) Add(x int) int {
  return c.Value + x
}

func (c Calculator) Multiply(x int) int {
  return c.Value * x
}

func main() {
  calc := Calculator{Value: 5}
  t := reflect.TypeOf(calc)

  method := t.Method(0)
  fn := method.Func

  args := []reflect.Value{
    reflect.ValueOf(calc),
    reflect.ValueOf(3),
  }

  result := fn.Call(args)
  fmt.Println("Result:", result[0].Int())
}

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

go"Result: 15"

Пример перебора всех методов

Давайте переберем все методы типа и выведем их информацию:

gopackage main

import (
  "fmt"
  "reflect"
)

type Data struct {
  ID   int
  Name string
}

func (d Data) GetID() int {
  return d.ID
}

func (d Data) GetName() string {
  return d.Name
}

func (d Data) SetID(id int) {
  d.ID = id
}

func main() {
  var d Data
  t := reflect.TypeOf(d)

  fmt.Println("Number of methods:", t.NumMethod())

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

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

go"Number of methods: 3"
"Method 0: GetID (type: func(main.Data) int)"
"Method 1: GetName (type: func(main.Data) string)"
"Method 2: SetID (type: func(main.Data, int))"

Пример работы с указателем на тип

Давайте получим методы для указателя на структуру:

gopackage main

import (
  "fmt"
  "reflect"
)

type Counter struct {
  Count int
}

func (c *Counter) Increment() {
  c.Count++
}

func (c *Counter) GetCount() int {
  return c.Count
}

func main() {
  ptr := &Counter{Count: 0}
  t := reflect.TypeOf(ptr)

  fmt.Println("Type kind:", t.Kind())

  if t.Kind() == reflect.Ptr {
    elemType := t.Elem()
    fmt.Println("Number of methods:", elemType.NumMethod())

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

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

go"Type kind: ptr"
"Number of methods: 2"
"Method 0: GetCount (type: func(*main.Counter) int)"
"Method 1: Increment (type: func(*main.Counter))"

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

Давайте получим метод с проверкой выхода за границы:

gopackage main

import (
  "fmt"
  "reflect"
)

type Formatter struct {
  Data string
}

func (f Formatter) Format() string {
  return "Formatted: " + f.Data
}

func main() {
  var f Formatter
  t := reflect.TypeOf(f)

  numMethods := t.NumMethod()
  fmt.Println("Total methods:", numMethods)

  idx := 0
  if idx < numMethods {
    method := t.Method(idx)
    fmt.Println("Method found:", method.Name)
    fmt.Println("Method signature:", method.Type)
  } else {
    fmt.Println("Method index out of range")
  }

  idx = 10
  if idx < numMethods {
    method := t.Method(idx)
    fmt.Println("Method found:", method.Name)
  } else {
    fmt.Println("Method index out of range")
  }
}

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

go"Total methods: 1"
"Method found: Format"
"Method signature: func(main.Formatter) string"
"Method index out of range"

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

  • метод reflect.Type.NumMethod,
    который возвращает количество методов типа
  • метод reflect.Type.Method,
    который возвращает информацию о методе по индексу
  • метод reflect.Value.Method,
    который возвращает значение метода для вызова
  • метод reflect.Type.Field,
    который возвращает информацию о поле структуры