如何在Go中实例化未知类型的值?

时间:2017-01-18 18:39:23

标签: go reflection

我在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)我在控制器层中有一些函数,它们(通过约定)接收1个参数(指向struct的指针)并返回1个结果(指向struct的指针),例如:

func SomeHandler(request *Request) *Response{
    ...do something
    return &Response{"first","second","third"}
}

我需要什么:

我需要编写以参数形式接收的包装函数:

      
  1. 指向'控制器'功能的指针
  2.   
  3. http.ResponseWriter
  4.   
  5. * http.Request
  6. 此包装函数必须:

        
    1. 确定'controller'函数的参数类型
    2.   
    3. 确定“控制器”功能的结果类型
    4.   
    5. 从Body of * http.Request(从json解码)
    6. 实例化并填充参数值   
    7. 调用控制器函数,并在前一步参数
    8. 上实例化   
    9. 将上一步的结果写入http.ResponseWriter(编码为json)
    10. 包装器必须与任何类型的“控制器”功能一致才能正常工作 - 此功能的签名不同(不同的参数类型,不同的结果类型)

      有人可以帮我实现这个包装吗?

2 个答案:

答案 0 :(得分:1)

您正在做的事情有点奇怪,但reflect可以提供您需要的所有信息。

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

}

打印:

Param 0: string
Param 1: int32
Result 0: error

答案 1 :(得分: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: 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
}

请注意,第二步是不必要的。