How can I store values in map
which can be both Type
and []Type
?
I tried this:
mymap := make(map[string]interface{})
mymap["string"] = "word"
mymap["vector"] = append(mymap["vector"].([]interface{}), "earth")
But I have an error:
panic: interface conversion: interface {} is nil, not []interface {}
The purpose of such mymap
to use it for json.Marshal
to get json
object like this:
{
"string": "word",
"vector": [
"earth",
"sun"
]
}
This will work, but you MUST ALWAYS manually check if the item is in the map AND run type assertions and act on them differently. I suggest making a type and only using methods instead of operating on the map itself.
https://play.golang.org/p/e2SFTN70F4v
var ErrNotExists = errors.New("value doesn't exist")
var ErrWrongType = errors.New("variable is wrong type")
type MyMap map[string]interface{}
func(m MyMap) IsArray(key string) bool {
val, ok := m[key]
if !ok {
return false
}
_, ok = val.([]string)
return ok
}
func(m MyMap) Exists(key string) bool {
_, ok := m[key]
return ok
}
func(m MyMap) SetString(key, value string) {
m[key] = value
}
func(m MyMap) SetArray(key string, value []string) {
m[key] = value
}
func(m MyMap) GetString(key string) (string, error) {
v, ok := m[key]
if !ok {
return "", ErrNotExists
}
realVal, ok := v.(string)
if !ok {
return "", ErrWrongType
}
return realVal, nil
}
func(m MyMap) GetArray(key string) ([]string, error) {
v, ok := m[key]
if !ok {
return nil, ErrNotExists
}
realVal, ok := v.([]string)
if !ok {
return nil, ErrWrongType
}
return realVal, nil
}
func(m MyMap) AppendArray(key string, toAppend []string) error {
v, ok := m[key]
if !ok {
return ErrNotExists
}
realVal, ok := v.([]string)
if !ok {
return ErrWrongType
}
m[key] = append(realVal, toAppend...)
return nil
}
func main() {
m := make(MyMap)
m.SetString("string","hello")
m.SetArray("array",[]string{"hi","there"})
fmt.Println(m)
fmt.Println(m.IsArray("string"), m.IsArray("array"))
s, err := m.GetString("string")
if err != nil { // handle
fmt.Println(err)
}
a, err := m.GetArray("array")
if err != nil { // handle
fmt.Println(err)
}
fmt.Println(s,a)
m.AppendArray("array", []string{"all","you","people"})
a, err = m.GetArray("array")
if err != nil { // handle
fmt.Println(err)
}
fmt.Println(a)
}
You can do something like this by defining JSON encoding processing of the value of map.
https://play.golang.org/p/1IW_hx8clhM
package main
import (
"encoding/json"
"fmt"
)
type MyMap map[string]MyValue
func (m MyMap) Put(k, v string) {
if list, ok := m[k]; ok {
m[k] = append(list, v)
} else {
m[k] = []string{v}
}
}
type MyValue []string
func (m MyValue) MarshalJSON() ([]byte, error) {
if len(m) == 1 {
return json.Marshal(m[0])
} else {
return json.Marshal([]string(m))
}
}
func main() {
m := make(MyMap)
m.Put("string", "word")
m.Put("vector", "earth")
m.Put("vector", "sun")
if data, err := json.Marshal(m); err == nil {
fmt.Println(string(data))
}
}