If you need to unmarshall to a variable type, the easiest way is to unmarshal into a map[string]interface{}
and type-assert (or in this case, type-switch) your way out.
func Unmarshal(data []byte) (map[string]Item, error) {
var d struct {
Items interface{} `json:"items"`
}
if err := json.Unmarshal(data, &d); err != nil {
return nil, err
}
switch dv := d.Items.(type) {
case []interface{}:
if len(dv) == 0 {
return nil, nil
}
case map[string]interface{}:
m := make(map[string]Item)
for k, v := range dv {
m[k] = Item(v)
}
return m, nil
}
// fallthrough return if different type, or non-empty array
// Could have put this in a default case, but this catches non-empty arrays too
return nil, fmt.Errorf("unexpected type in json")
}
Here's an example showing it works for both of your provided examples: https://play.golang.org/p/c0oZX2-xpN