Converti Go map in json


94

Ho provato a convertire la mia mappa Go in una stringa json con encoding/jsonMarshal, ma il risultato è stato una stringa vuota.

Ecco il mio codice:

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)
}

Il mio output è:

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}]

[]

Non so davvero dove sbaglio. Grazie per l'aiuto.


30
Si prega di non votare negativamente senza dare un commento. Penso che la domanda sia una buona domanda (+1): contiene tutto il codice, contiene una domanda precisa, l'output, ... È totalmente in tema e l'OP ha fatto molti sforzi per porre una buona domanda. È davvero un peccato avere i voti negativi qui!
topskip

4
Il problema deriva dal fatto che il PO ignora esplicitamente l'errore che avrebbe risposto immediatamente alla domanda.
JimB

3
Sono chiaramente coscienzioso di essermi sbagliato. Due errori in una domanda. Puoi star certo che non li ripeterò.
Cronos87

Risposte:


110

Se avessi rilevato l'errore, avresti visto questo:

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

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

Il fatto è che non puoi usare numeri interi come chiavi in ​​JSON; è vietato. Invece, puoi convertire questi valori in stringhe in anticipo, ad esempio usando strconv.Itoa.

Vedi questo post per maggiori dettagli: https://stackoverflow.com/a/24284721/2679935


3
Qui puoi vedere come vengono mappati i tipi: golang.org/pkg/encoding/json/#Unmarshal Potresti invece usare uno slice, che verrà mappato su un array JSON. Inoltre: controlla sempre gli errori;)
seong

2
Immagino che il comportamento sia cambiato. Vedere golang.org/pkg/encoding/json/#Unmarshal per "Il tipo di chiave della mappa deve essere una stringa, un tipo intero o implementare encoding.TextMarshaler."
Ashhar Hasan

@AshharHasan Apparentemente è cambiato in Go 1.7 ( golang.org/doc/go1.7#encoding_json ), ma continua a non fare quello che ti aspetteresti: play.golang.org/p/0aFaQ_ByOk
julienc

c'è un modo per farlo con una sync.Map?
Shahrukh Mohammad

@ShahrukhMohammad Non uso Go da anni, non sarò in grado di rispondere alla tua domanda ... Magari prova a creare una nuova domanda su SO!
julienc

27

In realtà ti dice cosa c'è che non va, ma l'hai ignorato perché non hai controllato l'errore restituito da json.Marshal.

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

Le specifiche JSON non supportano nulla tranne le stringhe per le chiavi degli oggetti, mentre javascript non sarà pignolo al riguardo, è comunque illegale.

Hai due opzioni:

1 Usa map[string]Fooe converti l'indice in stringa (usando fmt.Sprint per esempio):

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 Usa semplicemente uno slice (array 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


4
Hai ragione. È un errore vergognoso ... Non so davvero perché ho usato un int per una chiave Json ... Grazie per i tuoi esempi.
Cronos87

2

Poiché questa domanda è stata posta / l'ultima risposta, il supporto per i tipi di chiave non stringa per le mappe per json Marshal / UnMarshal è stato aggiunto tramite l'uso delle interfacce TextMarshaler e TextUnmarshaler qui . Potresti semplicemente implementare queste interfacce per i tuoi tipi di chiave e quindi json.Marshalfunzionerebbero come previsto.

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)
}

Produzione:

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}]
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.