Konversi Go map ke json

100

Saya mencoba untuk mengubah peta Go saya menjadi string json dengan encoding/jsonMarshal, tetapi hasilnya adalah string kosong.

Ini kode saya:

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

Output saya adalah:

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

[]

Saya benar-benar tidak tahu di mana saya salah. Terima kasih untuk bantuannya.

Cronos87
sumber
32
Tolong jangan downvote tanpa memberikan komentar. Saya pikir pertanyaannya adalah pertanyaan yang bagus (+1): berisi semua kode, berisi pertanyaan yang tepat, keluaran, ... Ini benar-benar sesuai topik dan OP telah berusaha keras untuk mengajukan pertanyaan yang bagus. Sungguh memalukan memiliki suara negatif di sini!
topskip
4
Masalahnya memang berasal dari fakta bahwa OP secara eksplisit mengabaikan kesalahan yang akan menjawab pertanyaan dengan segera.
JimB
3
Saya jelas sangat berhati-hati, saya salah. Dua kesalahan dalam satu pertanyaan. Anda dapat yakin bahwa saya tidak akan mengulanginya.
Cronos87

Jawaban:

116

Jika Anda telah mengetahui kesalahan tersebut, Anda akan melihat ini:

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

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

Masalahnya adalah Anda tidak dapat menggunakan integer sebagai kunci di JSON; itu dilarang. Sebagai gantinya, Anda dapat mengonversi nilai ini menjadi string sebelumnya, misalnya menggunakanstrconv.Itoa .

Lihat posting ini untuk lebih jelasnya: https://stackoverflow.com/a/24284721/2679935

julienc.dll
sumber
3
Di sini Anda dapat melihat bagaimana tipe map: golang.org/pkg/encoding/json/#Unmarshal Anda dapat menggunakan slice, yang akan dipetakan ke array JSON. Juga: selalu periksa kesalahan;)
seong
2
Saya kira perilakunya telah berubah. Lihat golang.org/pkg/encoding/json/#Unmarshal untuk "Jenis kunci peta harus berupa string, jenis integer, atau implementasikan encoding.TextMarshaler."
Ashhar Hasan
@AshharHasan Rupanya itu berubah di Go 1.7 ( golang.org/doc/go1.7#encoding_json ), tetapi masih tidak melakukan apa yang Anda harapkan: play.golang.org/p/0aFaQ_ByOk
julienc
apakah ada cara untuk melakukan ini dengan sync.Map?
Shahrukh Mohammad
@ShahrukhMohammad Saya sudah bertahun-tahun tidak menggunakan Go, saya tidak dapat menjawab pertanyaan Anda ... Mungkin coba buat pertanyaan baru di SO!
julienc
27

Ini sebenarnya memberi tahu Anda apa yang salah, tetapi Anda mengabaikannya karena Anda tidak memeriksa kesalahan yang dikembalikan json.Marshal.

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

Spesifikasi JSON tidak mendukung apa pun kecuali string untuk kunci objek, sementara javascript tidak akan merepotkan, itu masih ilegal.

Anda memiliki dua pilihan:

1 Gunakan map[string]Foodan ubah indeks menjadi string (menggunakan fmt.Sprint misalnya):

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 Cukup gunakan slice (javascript array):

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
sumber
4
Kamu benar. Ini adalah kesalahan yang memalukan ... Saya tidak begitu tahu mengapa saya menggunakan int untuk kunci json ... Terima kasih atas contoh Anda.
Cronos87
2

Sejak pertanyaan ini diminta / lalu menjawab, dukungan untuk jenis kunci string non untuk peta untuk json Marsekal / unmarshal telah ditambahkan melalui penggunaan TextMarshaler dan TextUnmarshaler antarmuka sini . Anda bisa menerapkan antarmuka ini untuk jenis kunci Anda dan kemudian json.Marshalakan berfungsi seperti yang diharapkan.

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

Keluaran:

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