Convertir une carte Go en json

94

J'ai essayé de convertir ma carte Go en une chaîne json avec encoding/jsonMarshal, mais cela a abouti à une chaîne vide.

Voici mon code:

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

Ma sortie est:

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

[]

Je ne sais vraiment pas où je me trompe. Merci de votre aide.

Cronos87
la source
30
Veuillez ne pas voter sans donner un commentaire. Je pense que la question est une bonne question (+1): elle contient tout le code, elle contient une question précise, la sortie, ... C'est totalement sur le sujet et l'OP a fait beaucoup d'efforts pour poser une bonne question. C'est vraiment dommage d'avoir les votes négatifs ici!
topskip
4
Le problème vient du fait que l'OP ignore explicitement l'erreur qui aurait répondu immédiatement à la question.
JimB
3
Je suis clairement consciencieux que j'avais tort. Deux erreurs dans une question. Vous pouvez être sûr que je ne les répéterai pas.
Cronos87

Réponses:

110

Si vous aviez détecté l'erreur, vous auriez vu ceci:

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

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

Le fait est que vous ne pouvez pas utiliser des entiers comme clés dans JSON; c'est interdit. Au lieu de cela, vous pouvez convertir ces valeurs en chaînes au préalable, par exemple en utilisant strconv.Itoa.

Voir cet article pour plus de détails: https://stackoverflow.com/a/24284721/2679935

Julienc
la source
3
Ici vous pouvez voir comment les types sont mappés : golang.org/pkg/encoding/json/#Unmarshal Vous pouvez utiliser une tranche à la place, qui correspondra à un tableau JSON. Aussi: toujours vérifier les erreurs;)
seong
2
Je suppose que le comportement a changé. Voir golang.org/pkg/encoding/json/#Unmarshal pour "Le type de clé de la carte doit être une chaîne, un type entier ou implémenter encoding.TextMarshaler."
Ashhar Hasan
@AshharHasan Apparemment, cela a changé dans Go 1.7 ( golang.org/doc/go1.7#encoding_json ), mais il ne fait toujours pas ce que vous attendez: play.golang.org/p/0aFaQ_ByOk
julienc
y a-t-il un moyen de faire cela avec une sync.Map?
Shahrukh Mohammad
@ShahrukhMohammad Je n'ai pas utilisé Go depuis des années, je ne pourrai pas répondre à votre question ... Essayez peut-être de créer une nouvelle question sur SO!
julienc
27

Il vous indique en fait ce qui ne va pas, mais vous l'avez ignoré car vous n'avez pas vérifié l'erreur renvoyée par json.Marshal.

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

La spécification JSON ne prend en charge rien sauf les chaînes pour les clés d'objet, alors que javascript ne sera pas difficile à ce sujet, il est toujours illégal.

Vous avez deux options:

1 Utilisez map[string]Fooet convertissez l'index en chaîne (en utilisant fmt.Sprint par exemple):

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 Utilisez simplement une tranche (tableau 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

OneOfOne
la source
4
Vous avez raison. C'est une erreur honteuse ... Je ne sais pas vraiment pourquoi j'ai utilisé un int pour une clé json ... Merci pour vos exemples.
Cronos87
2

Depuis que cette question a été posée / dernière réponse, la prise en charge des types de clés sans chaîne pour les cartes pour json Marshal / UnMarshal a été ajoutée via l'utilisation des interfaces TextMarshaler et TextUnmarshaler ici . Vous pouvez simplement implémenter ces interfaces pour vos types de clés, puis json.Marshalfonctionner comme prévu.

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

Production:

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}]
vigueur
la source