使用名称和参数通过Reflect调用方法

使用名称和参数通过Reflect调用方法

本文介绍了使用名称和参数通过Reflect调用方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是使用Go Reflect调用函数的后续操作.

为了简化这个问题,我想尽了一切办法,对一些值进行了硬编码,并希望〜并没有使过程变得不清楚.我在底部附近的代码"method.Call(env)"上遇到错误.

To simplify the question I cut out what I could, hard coded some values and ~hopefully~ didn't make it unclear in the process. I'm getting an error on the code "method.Call(env)" near the bottom.

理想情况下,我想做的就是尽量减少反射的使用,这与ThunderCat在上一行问题上所做的类似:

Ideally what I would like to do is minimize the use of reflection similarly how ThunderCat did on the previous question with the line:

method := miType.Method(i).Func.Interface().(func(core.ModuleInfo) core.ModuleInfo)

,但是如果不可能,那么最简单的方法就可以了.抱歉,如果这似乎是一个基本问题,我对Go还是很陌生.

but if that's not possible the simplest way it can be done would be perfectly fine. If this seems like a basic question, my apologies, I am very new to Go.

我得到的错误是:

cannot use env (type Environment) as type []reflect.Value in argument to method.Call

这是因为我想像上一个问题一样对具有正确签名的函数断言,但是经过一番尝试之后,我还没有完全理解它.

which is because I would like to assert the method to the function with the correct signature as was done on the previous quesiton but after quite a bit of playing around I just haven't quite got it.

简化代码:

package main

import (
  "flag"
  "fmt"
  "reflect"
)

type CommandLineFlags struct {
  Debug *bool
}

type Environment struct {
  CLF CommandLineFlags
}

type ModuleInfo struct {
  Initialize bool   // Flag: True of module has Initialization function and it should be called. Default: false
  Module     string // Name of the module. No need to hard code, will be set during initialization.
}

type ModuleInit struct{}

func main() {
  var env Environment

  env.CLF.Debug = flag.Bool("dbg", false, "Enables Debug Messages")
  flag.Parse()

  modules := make([]ModuleInfo, 1)
  modules[0].Initialize = true
  modules[0].Module = "logger"

  miValue := reflect.ValueOf(ModuleInit{})
  // miType := reflect.TypeOf(ModuleInit{})
  for _, m := range modules {
    if m.Initialize {
      funcName := m.Module + "Init"
      method := miValue.MethodByName(funcName)
      fmt.Println(funcName)
      // Would like to do something like this
      //    ...Func.Interface().(func(core.ModuleInit) core.ModuleInit)
      // like is done with the referenced quesiton above so as to minimize the use of reflect calls.
      method.Call(env)
    }
  }
}

func (mi ModuleInit) LoggerInit(env *Environment) {
  var debugEnabled = *env.CLF.Debug
  // ...and more stuff.
}

推荐答案

该方法的类型为 func(* Environment).声明为该类型并致电:

The method has the type func(*Environment). Assert to that type and call:

modules := make([]ModuleInfo, 1)
modules[0].Initialize = true
modules[0].Module = "Logger"

miValue := reflect.ValueOf(ModuleInit{})
for _, m := range modules {
    if m.Initialize {
        funcName := m.Module + "Init"
        method := miValue.MethodByName(funcName).Interface().(func(*Environment))
        method(&env)
    }
}

在操场上运行.

(已修复两个问题:该模块应为"Logger" ,而不是"logger" ,方法采用的是 * Environment ,而不是环境.)

(Note two issues fixed: The module should be "Logger", not "logger", method takes a *Environment, not an Environment.)

如果找不到该方法或该方法的类型不正确,则上面的代码将出现恐慌.这是带有防止恐慌的检查代码:

The code above will panic if the method is not found or does not have the correct type. Here's the code with checks to prevent a panic:

modules := make([]ModuleInfo, 1)
modules[0].Initialize = true
modules[0].Module = "Logger"

miValue := reflect.ValueOf(ModuleInit{})
for _, m := range modules {
    if m.Initialize {
        funcName := m.Module + "Init"
        method := miValue.MethodByName(funcName)
        if !method.IsValid() {
            fmt.Printf("method %s not found", funcName)
            continue
        }
        fn, ok := method.Interface().(func(*Environment))
        if !ok {
            fmt.Println("method is not func(*Environment)")
            continue
        }
        fn(&env)
    }
}

在操场上运行.

这篇关于使用名称和参数通过Reflect调用方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-30 23:28