动态确定Go中的函数参数

时间:2014-11-05 02:17:18

标签: function reflection go

有没有办法以编程方式确定Go中函数的参数(序列和类型)?

我想动态地将HTTP请求转换为方法/ func调用,以避免编写重复的编组代码(是的,我知道我需要非常小心我暴露的方法以及可能涉及的安全风险)。如果我可以检查函数所需的参数,从请求中解析适当的值然后动态调用函数(看起来最后一步将使用reflect.Value.Call - 至少那部分似乎是直的),这似乎是可能的。向前)。

编辑:能够这样做的好处是你可以创建一个适合直接在Go和远程使用的方法。例如,如果您有这样的函数:

func UpdatePerson(p *Person) error { ... }

这显然可以在Go中使用;我希望能够通过HTTP公开外部。

使用json-rpc接近但看起来会(在某些情况下)需要一些更加苛刻的结构用于它上面的i / o。

编辑2:基本上我有一整套CRUD要编写,我想暴露部分DAO,而不必编写所有这些疯狂的编组编码来创建另一个处理HTTP内容的层。 (对于一些安全性敏感的东西,我需要更仔细地编写内容,但我的许多DAO函数应该直接从浏览器“ - 也可以从Go”调用。)json-rpc满足第一个要求,但不是必然是第二个。

2 个答案:

答案 0 :(得分:2)

如果我理解您要做的事情,那么您正在寻找json-rpc。下面是一个非常简单的如何使用它的例子:

package main

import (
  "github.com/gorilla/rpc"
  "github.com/gorilla/rpc/json"
  "net/http"
)

type MyArgs struct {
    Msg string
}

type MyResponse struct {
    Msg string
}

type MyService struct{}

func (h *MyService) Test(r *http.Request, args *MyArgs, response *MyResponse) error {
    response.Msg = "Received: " + args.Msg
    return nil
}

func main() {
    s := rpc.NewServer()
    s.RegisterCodec(json.NewCodec(), "application/json")
    s.RegisterService(new(MyService), "")
    http.Handle("/rpc", s)
    http.ListenAndServe(":10000", nil)
}

用卷曲测试:

curl -X POST -H "Content-Type: application/json" \
-d '{"method":"MyService.Test","params":[{"Msg":"Test"}], "id":"1"}' \
http://localhost:10000/rpc

响应:

{"result":{"Msg":"Received: Test"},"error":null,"id":"1"}

编辑:

似乎有点混乱 - 你不需要Go两端 - 你可以使用jQuery从浏览器中调用方法,如下所示:

$.ajax({
  url: '/rpc',
  type:"POST",
  data: JSON.stringify({"method":"MyService.Test","params":[{"Msg":"Test"}], "id":"1"}),
  contentType:"application/json; charset=utf-8",
  dataType:"json",
  success: function(data){
      console.log(data);
  }
});

答案 1 :(得分:2)

您可以使用reflect package确定功能的参数。例如:

// argument is interface{} so we can accept functions of any signature
func printArguments(f interface{}) {
    t := reflect.TypeOf(f)
    fmt.Println("Function arguments:")
    for i := 0; i < t.NumIn(); i++ {
        fmt.Printf(" %d. %v\n", i, t.In(i))
    }
    fmt.Println("Function return values:")
    for i := 0; i < t.NumOut(); i++ {
        fmt.Printf(" %d. %v\n", i, t.Out(i))
    }
}

InOut函数分别返回表示参数和返回值类型的reflect.Type值。您可以使用此类型信息构造Value个对象的参数向量,以使用。

调用该函数

您可以在此处使用此示例:http://play.golang.org/p/qLThrI_Cw9