实现一个通用的参数方法

我在 Go 中有代码,其中包括许多执行方法。每个方法都接收它自己的参数结构。我希望调度程序使用其相关结构调用每个方法。


调度程序接收执行方法的名称,以及参数结构的 JSON。然后,它使用反射来构建结构,并调用方法。


问题是我得到编译错误,除非我使用空接口创建执行方法。在下面的示例中,我有 2 个执行方法: api1 正在编译,但使用的是空接口和显式转换。api2 是我想要做的,但它因编译错误而失败:


不能在赋值中使用 api2 (type func(Api2Parameters)) 作为 Api 类型


如何使 api2 使用编译?


import (

    "encoding/json"

    "log"

    "reflect"

)


type Api func(arguments interface{})


type ApiDetails struct {

    Executor       *Api

    ParametersType reflect.Type

}


var Apis map[string]*ApiDetails


func RunApi(apiName string, data string) {

    api := Apis[apiName]

    parameters := reflect.New(api.ParametersType).Interface().(interface{})

    _ = json.Unmarshal([]byte(data), parameters)

    (*api.Executor)(parameters)

}


type Api1Parameters struct {

    Count1 int

    Id1    string

}


func api1(arguments interface{}) {

    parameters, _ := arguments.(*Api1Parameters)

    log.Printf("api1 parameters(%+v)", parameters)

}


type Api2Parameters struct {

    Count2 int

    Id2    string

}


func api2(arguments Api2Parameters) {

    log.Printf("api2 parameters(%+v)", arguments)

}


func Test() {

    // this assignment works fine

    var api_1 Api = api1

    Apis["api1"] = &ApiDetails{

        Executor:       &api_1,

        ParametersType: reflect.TypeOf(Api1Parameters{}),

    }


    // this assignment produce compile error

    var api_2 Api = api2

    Apis["api2"] = &ApiDetails{

        Executor:       &api_2,

        ParametersType: reflect.TypeOf(Api2Parameters{}),

    }


    RunApi("api1", `{"Count1":19, "Id1":"a"}`)

    RunApi("api2", `{"Count2":34, "Id2":"b"}`)

}


RISEBY
浏览 134回答 2
2回答

绝地无双

使用参数类型创建一个值,解组该值并调用该函数:var Apis = map[string]interface{}{    "api1": api1,    "api2": api2,}func RunApi(apiName string, data string) {    fv := reflect.ValueOf(Apis[apiName])    ft := fv.Type()    pin := reflect.New(ft.In(0))    _ = json.Unmarshal([]byte(data), pin.Interface())    fv.Call([]reflect.Value{pin.Elem()})}

牛魔王的故事

如果您想保持这种类型安全,可以将 JSON-to-args 转换推得更深一些:type Api func(string)type ApiDetails struct {    // Don't use *Api, that's a function pointer-pointer    Executor       Api}然后,使用闭包进行 JSON 转换:Apis["api1"] = &ApiDetails{        Executor: func(data string) {            var args ArgsForAPI1            json.Unmarshal([]byte(string),&args)            api1Implem(args)        }    }有了这个,你可以这样做:APIs["api1"].Executor( `{"Count1":19, "Id1":"a"}`)你可以改变RunApi做这样的事情。第二种选择是使用反射来做到这一点:type ApiDetails struct {    // Executor can accept any function signature    // Assume a function with  a single parameter    Executor     interface{}    ParametersType reflect.Type}然后,RunApi 函数可以使用反射构造一个结构并调用Executor:    parameters := reflect.New(api.ParametersType)    _ = json.Unmarshal([]byte(data), parameters.Interface{})    reflect.ValueOf(api.Executor).Call([]reflect.Value{parameters})这应该可以,但是如果你搞砸了,你只会得到运行时错误。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go