简体   繁体   中英

How to make parameter of function is a “generic” struct

For example, I want to write a method like this:

func parseData(rawData []json.RawMessage) []interface{} {
    var migrations []interface{}
    for _, migration := range rawData {
        // this is an custom struct
        command := UserCommand{}
        json.Unmarshal(migration, &command)
        migrations = append(migrations, command)
    }

    return migrations
}

The problem of this code is: If I don't want to parse UserCommand but any other such as ProductCommand , I must write the same code, only different at line: command := UserCommand{} . So my question is: how can I generic this code.

I have tried this solution but it doesn't work:

func parseData(rawData []json.RawMessage, class interface{}) []interface{} {
    var migrations []interface{}
    for _, migration := range rawData {
        command := class
        json.Unmarshal(migration, &command)
        migrations = append(migrations, command)
    }

    return migrations
}
// then I call this method
parseData(data, UserCommand{})

But it doesn't work. It return array of map[string]interface{} How can I fix this.

Edit:

Here is some my defined struct

type UserCommand struct {
    User string
    Info string
}
type ProductCommand struct {
    Name      string
    Quanlity  int
}
 // I want to be able to call this method parseData(data, UserCommand{}) 

It is possible to support this style of "generic" signature by using Go's reflect package.

package main

import (
    "encoding/json"
    "fmt"
    "reflect"
)

type UserCommand struct {
    User string
    Info string
}

type ProductCommand struct {
    Name     string
    Quantity int
}

func parseData(rawData []json.RawMessage, class interface{}) []interface{} {
    var parsed []interface{}
    for _, elem := range rawData {
        // Create a pointer to a new zero value of the same type as `class`.
        command := reflect.New(reflect.TypeOf(class))
        // Pass a pointer to the new value to `json.Unmarshal`.
        json.Unmarshal(elem, command.Interface())
        // Insert the pointed-to new value into the output slice.
        parsed = append(parsed, command.Elem().Interface())
    }
    return parsed
}

func main() {
    data := []json.RawMessage{
        json.RawMessage(`{"User":"u1","Info":"i1"}`),
        json.RawMessage(`{"User":"u2","Info":"i2"}`),
    }
    parsed := parseData(data, UserCommand{})
    fmt.Printf("%#v\n", parsed)

    data = []json.RawMessage{
        json.RawMessage(`{"Name":"n1","Quantity":1}`),
        json.RawMessage(`{"Name":"n2","Quantity":2}`),
    }
    parsed = parseData(data, ProductCommand{})
    fmt.Printf("%#v\n", parsed)
}

The output shows that the first parseData call has parsed two UserCommand structs and the second call has parsed two ProductCommand structs.

[]interface {}{main.UserCommand{User:"u1", Info:"i1"}, main.UserCommand{User:"u2", Info:"i2"}}
[]interface {}{main.ProductCommand{Name:"n1", Quantity:1}, main.ProductCommand{Name:"n2", Quantity:2}}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM