为了账号安全,请及时绑定邮箱和手机立即绑定

实现一个通用的参数方法

实现一个通用的参数方法

Go
RISEBY 2022-05-05 18:01:57
我在 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]*ApiDetailsfunc 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"}`)}
查看完整描述

2 回答

?
绝地无双

TA贡献1946条经验 获得超4个赞

使用参数类型创建一个值,解组该值并调用该函数:


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()})

}


查看完整回答
反对 回复 2022-05-05
?
牛魔王的故事

TA贡献1830条经验 获得超3个赞

如果您想保持这种类型安全,可以将 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})

这应该可以,但是如果你搞砸了,你只会得到运行时错误。


查看完整回答
反对 回复 2022-05-05
  • 2 回答
  • 0 关注
  • 133 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信