Вызов функции с помощью Go Reflect - PullRequest
0 голосов
/ 26 октября 2018

Мне было интересно, можно ли не знать имя функции, но в любом случае вызвать его и получить из него значения.Это привело меня к пакету рефлексии, и я подошел довольно близко, но я не уверен насчет последнего шага - если он есть.Опять же, пожалуйста, прости меня, если я упускаю что-то очевидное, это моя первая попытка сделать что-то в Go, кроме как настроить его.

Конечно, будучи скомпилированным языком, нет необходимости перебирать вещи, чтобы найти функциюимена, я знаю их все, но это то, что я хочу увидеть, если это возможно ... Я играю и учусь.

Ниже приведен код.Что я действительно хотел бы сделать, так это в главной строке извлечь значения, установленные в ModuleBoot () <«1.0012», 23> и SomethingBoot () <«1.0000», 10>, но пока все, что я могу получить, - это информация о структуре.Возможно, так оно и есть, но, возможно, есть шаг или изменение, которое может заставить его перейти к следующему шагу.

Надеюсь, я правильно скопировал весь соответствующий код, чтобы он компилировался как:

// Using: go version go1.9.7 linux/amd64
=======================================
FILE: main.go
=======================================
package main

import (
  "fmt"
  "reflect"
  "playing/modules/core"
)

func main() {

  miType := reflect.TypeOf(core.ModuleInfo{})

  fmt.Println("")

  for i := 0; i < miType.NumMethod(); i++ {
    method := miType.Method(i)
    fmt.Println(method.Name)

    in := make([]reflect.Value, method.Type.NumIn())
    in[0] = reflect.ValueOf(core.ModuleInfo{})
    //fmt.Println("Params in:", method.Type.NumIn(), "Params out:", method.Type.NumOut())

    mi := method.Func.Call(in)
    fmt.Println("mi:", mi)

    fmt.Println("")
  }
}

=======================================
FILE: playing/modules/core/something.go
=======================================
package core

func (mi ModuleInfo) SomethingBoot() ModuleInfo {
  mi.Version = "1.0000"
  mi.Priority = 10
  return mi
}

=======================================
FILE: playing/modules/core/modules.go
=======================================
package core

type ModuleInfo struct {
  Version string
  Priority int
}

func (mi ModuleInfo) ModuleBoot() ModuleInfo {
  mi.Version = "1.0012"
  mi.Priority = 23
  return mi
}

Вывод, который я получил от этого:

Started delve with config "Debug"

SomethingBoot
mi: [<core.ModuleInfo Value>]

ModuleBoot
mi: [<core.ModuleInfo Value>]

delve closed with code 0

Ответы [ 2 ]

0 голосов
/ 26 октября 2018

Go изначально поддерживает функции как значения;для этого вам не нужно рефлексия.

В частности, если вы сделаете две функции верхнего уровня (не привязанные к структуре):

package core
type ModuleInfo struct { ... }
func SomethingBoot() ModuleInfo
func ModuleBoot() ModuleInfo

Тогда вы можетенапишите функцию, которая принимает функцию в качестве параметра:

func PrintVersion(func booter() core.ModuleInfo) {
        mi := booter()
        fmt.Printf("version %s\n", mi.Version)
}

И вы можете просто передать ранее существующие функции в качестве параметров:

PrintVersion(core.SomethingBoot)
PrintVersion(core.ModuleBoot)

Обратите внимание, что после скобок нетимя функции: вы передаете саму функцию в качестве параметра, не вызывая функцию и передавая ее возвращаемое значение.

0 голосов
/ 26 октября 2018

Чтобы получить возвращаемое значение в виде ModuleInfo, получите базовое значение первого возвращаемого значения и введите assert это значение интерфейса для ModuleInfo:

// mi has type core.ModuleInfo
mi := method.Func.Call(in)[0].Interface().(core.ModuleInfo)

Запустите его на игровой площадке .

Вы можете вырезать часть кода отражения, набрав тип метода для функции с правильной сигнатурой и вызвав эту функцию напрямую:

for i := 0; i < miType.NumMethod(); i++ {
    method := miType.Method(i).Func.Interface().(func(core.ModuleInfo) core.ModuleInfo)
    mi := method(core.ModuleInfo{})
    fmt.Println("Version", mi.Version)
    fmt.Println("Priority", mi.Priority)
    fmt.Println("")
}

Запустите его на детской площадке

...