英文:
How to instantiate value of unknown type in Go?
问题
我在golang中开发了一些服务器。我试图创建一些包装函数,以便将来能够帮助我。
我有以下内容:
1)我有一些DTO结构体,例如:
type Request struct {
Field1 string `json:"field1"`
Field2 string `json:"field2"`
}
type Response struct {
Field1 string `json:"field1"`
Field2 string `json:"field2"`
Field3 string `json:"field3"`
}
2)我有一些函数,在控制器层中,按照约定,它们接收一个参数(指向结构体的指针)并返回一个结果(指向结构体的指针),例如:
func SomeHandler(request *Request) *Response{
...做一些事情
return &Response{"first","second","third"}
}
我需要:
我需要编写一个包装函数,它接收以下参数:
- 'controller'函数的指针
- http.ResponseWriter
- *http.Request
这个包装函数必须:
- 确定'controller'函数的参数类型
- 确定'controller'函数的结果类型
- 从*http.Request的Body中实例化并填充参数值(从json解码)
- 使用在上一步中实例化的参数调用控制器函数
- 将上一步的结果写入http.ResponseWriter(以json格式编码)
包装函数必须能够正确处理任何类型的'controller'函数-这些函数的签名是不同的(参数类型不同,结果类型不同)
有人可以帮我实现这个包装函数吗?
英文:
I develop some server in golang. I try to create some wrapper-function, which can helps me in future.
What I have:
-
I had some DTO structs, for example:
type Request struct {
Field1 stringjson:"field1"
Field2 stringjson:"field2"
}type Response struct {
Field1 stringjson:"field1"
Field2 stringjson:"field2"
Field3 stringjson:"field3"
} -
I had some functions, in controller layer, which (by conventions) receives 1 argument (pointer to struct) and returns 1 result (pointer to struct), for example:
func SomeHandler(request *Request) *Response{
...do something
return &Response{"first","second","third"}
}
What I need:
I need to write wrapper function which receives as argument:
<ol>
<li>pointer to 'controller' function</li>
<li>http.ResponseWriter</li>
<li>*http.Request</li>
</ol>
This wrapper function must:
<ol>
<li>Determine type of argument of 'controller' function</li>
<li>Determine type of result of 'controller' function</li>
<li>Instantiate and fill argument value from Body of *http.Request (decode from json) </li>
<li>Call controller Function with instantiated on previous step argument</li>
<li>Write results of previous step into http.ResponseWriter (encoded as json)</li>
</ol>
Wrapper must work correct with any types of 'controller' functions - signatures of this functions is different (different argument type, different result type)
Can anybody help me with implementing of this wrapper?
答案1
得分: 2
你正在做一些有点奇怪的事情,但reflect
可以提供你所需的所有信息。
func myFunction(a string, b int32) error {
return nil
}
func myWrapper(mystery interface{}) {
typ := reflect.TypeOf(mystery)
// 在操作 In(i) 之前,先检查 typ.Kind;
for i := 0; i < typ.NumIn(); i++ {
fmt.Printf("Param %d: %v\n", i, typ.In(i))
}
for i := 0; i < typ.NumOut(); i++ {
fmt.Printf("Result %d: %v\n", i, typ.Out(i))
}
}
这将打印出:
Param 0: string
Param 1: int32
Result 0: error
英文:
What you're doing is a bit weird but reflect
can provide all the info you need.
func myFunction(a string, b int32) error {
return nil
}
func myWrapper(mystery interface{}) {
typ := reflect.TypeOf(mystery)
// Check typ.Kind before playing with In(i);
for i := 0; i < typ.NumIn(); i++ {
fmt.Printf("Param %d: %v\n", i, typ.In(i))
}
for i := 0; i < typ.NumOut(); i++ {
fmt.Printf("Result %d: %v\n", i, typ.Out(i))
}
}
This prints:
Param 0: string
Param 1: int32
Result 0: error
答案2
得分: 0
应该可以使用类似这样的代码(未经测试):
func wrapper(ctlr interface{}, w http.ResponseWriter, r *http.Request) error {
tpe := reflect.TypeOf(ctlr)
if tpe.Kind() != reflect.Func || tpe.NumIn() != 1 || tpe.NumOut() != 1 {
// TODO: 处理错误的 ctlr 类型
}
// 1. 确定 'controller' 函数的参数类型
argt := tpe.In(0)
// 2. 确定 'controller' 函数的返回类型
// rest := tpe.Out(0) // 这一步是不必要的,可以注释掉
// 3. 从 *http.Request 的 Body 中实例化并填充参数值(从 json 解码)
arg := reflect.Zero(argt)
err := json.NewDecoder(r.Body).Decode(&arg)
if err != nil {
// TODO: 处理错误
}
// 4. 使用前一步实例化的参数调用 controller 函数
resv := reflect.ValueOf(ctlr).Call([]reflect.Value{arg})[0]
// 5. 将前一步的结果写入 http.ResponseWriter(以 json 编码)
err = json.NewEncoder(w).Encode(resv.Interface())
if err != nil {
// TODO: 处理错误
}
return nil
}
请注意,第二步是不必要的。
英文:
Something like this should work (untested):
func wrapper(ctlr interface{}, w http.ResponseWriter, r *http.Request) error {
tpe := reflect.TypeOf(ctlr)
if tpe.Kind() != reflect.Func || tpe.NumIn() != 1 || tpe.NumOut() != 1 {
// TODO: handle wrong ctlr type
}
// 1. Determine type of argument of 'controller' function
argt := tpe.In(0)
// 2. Determine type of result of 'controller' function
// rest := tpe.Out(0) // commented out since it's useless
// 3. Instantiate and fill argument value from Body of *http.Request (decode from json)
arg := reflect.Zero(argt)
err := json.NewDecoder(r.Body).Decode(&arg)
if err != nil {
// TODO: handle err
}
// 4. Call controller Function with instantiated on previous step argument
resv := reflect.ValueOf(ctlr).Call([]reflect.Value{arg})[0]
// 5. Write results of previous step into http.ResponseWriter (encoded as json)
err = json.NewEncoder(w).Encode(resv.Interface())
if err != nil {
// TODO: handle err
}
return nil
}
Note that the second step is unnecessary.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论