亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

使用 Go Reflect 按名稱和參數調用方法

使用 Go Reflect 按名稱和參數調用方法

Go
慕尼黑8549860 2023-05-04 16:39:43
這是Calling a function with Go Reflect的后續。為了簡化問題,我刪掉了我能刪掉的內容,對一些值進行了硬編碼,并且~希望~在這個過程中沒有讓它變得不清楚。我在底部附近的代碼“method.Call(env)”上遇到錯誤。理想情況下,我想做的是盡量減少反射的使用,就像 ThunderCat 在上一個問題中所做的那樣:method := miType.Method(i).Func.Interface().(func(core.ModuleInfo) core.ModuleInfo)但如果那不可能,那么最簡單的方法就可以了。如果這看起來像是一個基本問題,我很抱歉,我是 Go 的新手。我得到的錯誤是:cannot use env (type Environment) as type []reflect.Value in argument to method.Call這是因為我想用正確的簽名斷言函數的方法,就像在上一個問題中所做的那樣,但是經過相當多的嘗試之后,我還是不太明白。簡化代碼:package mainimport (  "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.}
查看完整描述

4 回答

?
白板的微信

TA貢獻1883條經驗 獲得超3個贊

該方法的類型為func(*Environment)。?斷言該類型并調用:

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,而不是Environment。)

如果找不到該方法或沒有正確的類型,上面的代碼將崩潰。這是帶有檢查以防止恐慌的代碼:

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)

? ? }

}


查看完整回答
反對 回復 2023-05-04
?
喵喔喔

TA貢獻1735條經驗 獲得超5個贊

OP代碼中有幾個錯誤,

  • 函數名稱未正確生成,

  • 反映的方法實例沒有正確檢查有效性,

  • LoggerInit 的 env 參數是一個指針,傳入了一個值,

  • 方法調用未正確完成。

這是固定版本 ( https://play.golang.org/p/FIEc6bTvGWJ )。

package main


import (

    "flag"

    "fmt"

    "log"

    "reflect"

    "strings"

)


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 := strings.Title(m.Module) + "Init"

            method := miValue.MethodByName(funcName)

            log.Printf("%#v %v\n", method, funcName)

            if !method.IsValid() || method.IsNil() {

                break

            }

            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.

            out := method.Call([]reflect.Value{reflect.ValueOf(env)})

            fmt.Println(out) // A bunch of relfect.Values.

        }

    }

}


func (mi ModuleInit) LoggerInit(env Environment) {

    var debugEnabled = *env.CLF.Debug

    // ...and more stuff.

    log.Println("LoggerInit ", debugEnabled)

}


查看完整回答
反對 回復 2023-05-04
?
四季花海

TA貢獻1811條經驗 獲得超5個贊

問題是傳遞的參數本身reflect.Value.Call必須是類型reflect.Value

func (v Value) Call(in []Value) []Value


查看完整回答
反對 回復 2023-05-04
?
慕姐8265434

TA貢獻1813條經驗 獲得超2個贊

您必須將env變量包裝在 a 中[]reflect.Value,因為reflect.Value.Call需要一片reflect.Value.

args := []reflect.Value{reflect.ValueOf(&env),}
method.Call(args)

另外,您的代碼中有一些錯別字:

modules[0].Module = "Logger"


查看完整回答
反對 回復 2023-05-04
  • 4 回答
  • 0 關注
  • 174 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號