将界面转换为另一个并复制内容

时间:2017-11-25 18:14:04

标签: go reflection types interface casting

我有以下方法:

func ValidateParam(conf map[string]interface{}, paramName string, out interface{}) error {
    param, ok := conf[paramName]

    if !ok {
        return errors.New("some error")
    }

    // ...
}

我希望能够这样称呼它:

myVar := "some text"
err := ValidateParam(conf, "my_var_param", &myVar)

myOtherVar := &MyStruct{}
err := ValidateParam(conf, "my_struct_param", myOtherVar)

这个想法是:

  • 使用conf地图
  • 获取参数
  • 检查此参数是否可以转换为与out
  • 相同的类型
  • 使用param
  • 水合out

=>它与json.Unmarshal(data, &myVar)或使用mgo query.Collection("col").One(&myVar)进行查询时的流程相同

我无法找到如何实现这一点,任何帮助都会受到欢迎。

干杯

1 个答案:

答案 0 :(得分:3)

一种选择是使用反射包:

基本思想是为输入和输出创建reflect.Values,检查输入是否可分配给输出然后分配。

func ValidateParam(conf map[string]interface{}, paramName string, out interface{}) error {
    param, ok := conf[paramName]

    if !ok {
        return errors.New("some error")
    }

    // Output is pointer to value.
    vo := reflect.ValueOf(out)
    if vo.Kind() != reflect.Ptr {
        return errors.New("out must be poitner")
    }
    vo = vo.Elem()  // deref ptr

    // Can input be assigned to output?
    vi := reflect.ValueOf(param)
    if !vi.Type().AssignableTo(vo.Type()) {
        return fmt.Errorf("param %s of type %v is not assignable to %v", paramName, vi.Type(), vo.Type())
    }

    vo.Set(vi)
    return nil
}

playground example