Go haritasını json'a dönüştür


100

Go haritamı encoding/jsonMarshal ile bir json dizesine dönüştürmeyi denedim , ancak boş bir dizeyle sonuçlandı.

İşte kodum:

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

Çıktım:

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

[]

Gerçekten nerede yanıldığımı bilmiyorum. Yardımın için teşekkürler.


32
Lütfen yorum yapmadan olumsuz oy vermeyin. Bence soru iyi bir soru (+1): tüm kodu içeriyor, kesin bir soru içeriyor, çıktı, ... Tamamen konu üzerine ve OP iyi bir soru sormak için çok çaba sarf etti. Burada olumsuz oyların olması gerçekten utanç verici!
14'ü

4
Sorun, OP'nin soruyu hemen yanıtlayacak olan hatayı açıkça görmezden gelmesinden kaynaklanmaktadır.
JimB

3
Açıkça vicdanlıyım, yanılmışım. Bir soruda iki hata. Onları tekrar etmeyeceğimden emin olabilirsiniz.
Cronos87

Yanıtlar:


116

Hatayı yakalamış olsaydın, şunu görürdün:

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

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

Mesele şu ki, JSON'da tamsayıları anahtar olarak kullanamazsınız; yasaktır. Bunun yerine, bu değerleri önceden dizelere dönüştürebilirsiniz, örneğin strconv.Itoa.

Daha fazla ayrıntı için bu gönderiye bakın: https://stackoverflow.com/a/24284721/2679935


3
Burada türlerin nasıl eşleştiğini görebilirsiniz: golang.org/pkg/encoding/json/#Unmarshal Bunun yerine, JSON dizisine eşlenecek bir dilim kullanabilirsiniz. Ayrıca: Her zaman hatalarını kontrol;)
seong

2
Sanırım davranış değişti. "Haritanın anahtar türü bir dizge, tamsayı türü veya kodlama.TextMarshaler uygulama olmalıdır" için golang.org/pkg/encoding/json/#Unmarshal adresine bakın .
Ashhar Hasan

@AshharHasan Görünüşe göre Go 1.7'de değişti ( golang.org/doc/go1.7#encoding_json ), ama yine de beklediğiniz şeyi yapmıyor: play.golang.org/p/0aFaQ_ByOk
julienc

bunu bir sync.Map ile yapmanın bir yolu var mı?
Shahrukh Mohammad

@ShahrukhMohammad Yıllardır Go kullanmadım, sorunuza cevap veremeyeceğim ... Belki SO'da yeni bir soru oluşturmayı deneyin!
julienc

27

Aslında size neyin yanlış olduğunu söyler, ancak bunu görmezden geldiniz çünkü dönen hatayı kontrol etmediniz json.Marshal.

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

JSON belirtimi, nesne anahtarları için dizeler dışında hiçbir şeyi desteklemez, ancak javascript bu konuda telaşlı olmaz, yine de yasa dışıdır.

İki seçeneğiniz var:

1 map[string]FooDizini kullanın ve dizeye dönüştürün (örneğin fmt.Sprint kullanarak):

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 Sadece bir dilim (javascript dizisi) kullanın:

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
Haklısın. Utanç verici bir hata ... json anahtarı için neden int kullandığımı gerçekten bilmiyorum ... Örnekleriniz için teşekkür ederim.
Cronos87

2

Bu soru sorulduğundan / son yanıtlandığından beri, json Marshal / UnMarshal için haritalar için dize olmayan anahtar türleri desteği, burada TextMarshaler ve TextUnmarshaler arabirimlerinin kullanılmasıyla eklenmiştir . Bu arabirimleri yalnızca anahtar türleriniz için uygulayabilir ve ardından beklendiği gibi çalışabilirsiniz.json.Marshal

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

Çıktı:

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}]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.