Aziule
Aziule

Reputation: 441

Converting interface into another and copy content

I've got the following method:

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

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

    // ...
}

I would like to be able to call it like so:

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

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

The idea is:

=> It is kind of the same process as for json.Unmarshal(data, &myVar) or when doing a query with mgo query.Collection("col").One(&myVar)

I can't find how to achieve this, any help would be more than welcome.

Cheers

Upvotes: 0

Views: 74

Answers (1)

Thundercat
Thundercat

Reputation: 120941

One option is to use the reflect package:

The basic idea is to create reflect.Values for input and output, check if input is assignable to output and then assign.

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

Upvotes: 3

Related Questions