Convertir mapa de Go a json

94

Intenté convertir mi mapa Go en una cadena json con encoding/jsonMarshal, pero resultó en una cadena vacía.

Aquí está mi código:

package main

import (
    "encoding/json"
    "fmt"
)

type Foo struct {
    Number int    `json:"number"`
    Title  string `json:"title"`
}

func main() {
    datas := make(map[int]Foo)

    for i := 0; i < 10; i++ {
        datas[i] = Foo{Number: 1, Title: "test"}
    }

    jsonString, _ := json.Marshal(datas)

    fmt.Println(datas)
    fmt.Println(jsonString)
}

Mi salida es:

map[9:{1 test} 2:{1 test} 7:{1 test} 3:{1 test} 4:{1 test} 5:{1 test} 6:{1 test} 8:{1 test} 0:{1 test} 1:{1 test}]

[]

Realmente no sé dónde me equivoco. Gracias por tu ayuda.

Cronos87
fuente
30
Por favor, no vote en contra sin dar un comentario. Creo que la pregunta es una buena pregunta (+1): contiene todo el código, contiene una pregunta precisa, el resultado, ... Está totalmente en el tema y el OP ha hecho un gran esfuerzo para hacer una buena pregunta. ¡Es realmente una pena tener los votos negativos aquí!
topskip
4
El problema surge del hecho de que el OP ignora explícitamente el error que habría respondido a la pregunta de inmediato.
JimB
3
Estoy claramente consciente de que estaba equivocado. Dos errores en una pregunta. Puede estar seguro de que no los repetiré.
Cronos87

Respuestas:

110

Si hubiera detectado el error, habría visto esto:

jsonString, err := json.Marshal(datas)
fmt.Println(err)

// [] json: unsupported type: map[int]main.Foo

El caso es que no puede usar números enteros como claves en JSON; está prohibido. En su lugar, puede convertir estos valores en cadenas de antemano, por ejemplo, utilizando strconv.Itoa.

Consulte esta publicación para obtener más detalles: https://stackoverflow.com/a/24284721/2679935

Julienc
fuente
3
Aquí puede ver cómo se asignan los tipos: golang.org/pkg/encoding/json/#Unmarshal En su lugar, podría usar un segmento, que se asignará a una matriz JSON. Además: siempre verifique si hay errores;)
seong
2
Supongo que el comportamiento ha cambiado. Consulte golang.org/pkg/encoding/json/#Unmarshal para ver "El tipo de clave del mapa debe ser una cadena, un tipo entero o implementar la codificación.TextMarshaler".
Ashhar Hasan
@AshharHasan Aparentemente cambió en Go 1.7 ( golang.org/doc/go1.7#encoding_json ), pero aún no hace lo que esperarías: play.golang.org/p/0aFaQ_ByOk
julienc
¿Hay alguna manera de hacer esto con un mapa de sincronización?
Shahrukh Mohammad
@ShahrukhMohammad No he usado Go en años, no podré responder a su pregunta ... ¡Quizás intente crear una nueva pregunta en SO!
julienc
27

En realidad, le dice qué está mal, pero lo ignoró porque no verificó el error devuelto json.Marshal.

json: unsupported type: map[int]main.Foo

La especificación JSON no admite nada excepto cadenas para claves de objeto, mientras que javascript no será exigente al respecto, sigue siendo ilegal.

Tienes dos opciones:

1 Utilice map[string]Fooy convierta el índice en una cadena (utilizando fmt.Sprint, por ejemplo):

datas := make(map[string]Foo, N)

for i := 0; i < 10; i++ {
    datas[fmt.Sprint(i)] = Foo{Number: 1, Title: "test"}
}
j, err := json.Marshal(datas)
fmt.Println(string(j), err)

2 Simplemente use un segmento (matriz javascript):

datas2 := make([]Foo, N)
for i := 0; i < 10; i++ {
    datas2[i] = Foo{Number: 1, Title: "test"}
}
j, err = json.Marshal(datas2)
fmt.Println(string(j), err)

playground

Uno de uno
fuente
4
Tienes razón. Es un error vergonzoso ... Realmente no sé por qué usé un int para una clave json ... Gracias por sus ejemplos.
Cronos87
2

Desde que se hizo esta pregunta / se respondió por última vez, se ha agregado soporte para tipos de claves que no son cadenas para mapas para json Marshal / UnMarshal mediante el uso de las interfaces TextMarshaler y TextUnmarshaler aquí . Simplemente podría implementar estas interfaces para sus tipos de clave y luego json.Marshalfuncionaría como se esperaba.

package main

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

// Num wraps the int value so that we can implement the TextMarshaler and TextUnmarshaler 
type Num int

func (n *Num) UnmarshalText(text []byte) error {
    i, err := strconv.Atoi(string(text))
    if err != nil {
        return err
    }
    *n = Num(i)
    return nil
}

func (n Num) MarshalText() (text []byte, err error) {
    return []byte(strconv.Itoa(int(n))), nil
}

type Foo struct {
    Number Num    `json:"number"`
    Title  string `json:"title"`
}

func main() {
    datas := make(map[Num]Foo)

    for i := 0; i < 10; i++ {
        datas[Num(i)] = Foo{Number: 1, Title: "test"}
    }

    jsonString, err := json.Marshal(datas)
    if err != nil {
        panic(err)
    }

    fmt.Println(datas)
    fmt.Println(jsonString)

    m := make(map[Num]Foo)
    err = json.Unmarshal(jsonString, &m)
    if err != nil {
        panic(err)
    }

    fmt.Println(m)
}

Salida:

map[1:{1 test} 2:{1 test} 4:{1 test} 7:{1 test} 8:{1 test} 9:{1 test} 0:{1 test} 3:{1 test} 5:{1 test} 6:{1 test}]
[123 34 48 34 58 123 34 110 117 109 98 101 114 34 58 34 49 34 44 34 116 105 116 108 101 34 58 34 116 101 115 116 34 125 44 34 49 34 58 123 34 110 117 109 98 101 114 34 58 34 49 34 44 34 116 105 116 108 101 34 58 34 116 101 115 116 34 125 44 34 50 34 58 123 34 110 117 109 98 101 114 34 58 34 49 34 44 34 116 105 116 108 101 34 58 34 116 101 115 116 34 125 44 34 51 34 58 123 34 110 117 109 98 101 114 34 58 34 49 34 44 34 116 105 116 108 101 34 58 34 116 101 115 116 34 125 44 34 52 34 58 123 34 110 117 109 98 101 114 34 58 34 49 34 44 34 116 105 116 108 101 34 58 34 116 101 115 116 34 125 44 34 53 34 58 123 34 110 117 109 98 101 114 34 58 34 49 34 44 34 116 105 116 108 101 34 58 34 116 101 115 116 34 125 44 34 54 34 58 123 34 110 117 109 98 101 114 34 58 34 49 34 44 34 116 105 116 108 101 34 58 34 116 101 115 116 34 125 44 34 55 34 58 123 34 110 117 109 98 101 114 34 58 34 49 34 44 34 116 105 116 108 101 34 58 34 116 101 115 116 34 125 44 34 56 34 58 123 34 110 117 109 98 101 114 34 58 34 49 34 44 34 116 105 116 108 101 34 58 34 116 101 115 116 34 125 44 34 57 34 58 123 34 110 117 109 98 101 114 34 58 34 49 34 44 34 116 105 116 108 101 34 58 34 116 101 115 116 34 125 125]
map[4:{1 test} 5:{1 test} 6:{1 test} 7:{1 test} 0:{1 test} 2:{1 test} 3:{1 test} 1:{1 test} 8:{1 test} 9:{1 test}]
empuje
fuente