Konwertuj Go map na json


100

Próbowałem przekonwertować moją mapę Go na ciąg json za pomocą encoding/jsonMarshal, ale spowodowało to pusty ciąg.

Oto mój kod:

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

Mój wynik to:

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

[]

Naprawdę nie wiem, gdzie się mylę. Dziękuję za pomoc.


32
Nie głosuj przeciwnie bez komentarza. Myślę, że pytanie jest dobre (+1): zawiera cały kod, zawiera precyzyjne pytanie, wynik ... Jest całkowicie na temat, a PO włożył wiele wysiłku, aby zadać dobre pytanie. Naprawdę szkoda mieć tutaj głosy przeciw!
topskip

4
Problem rzeczywiście wynika z faktu, że PO wyraźnie ignoruje błąd, który pozwoliłby na natychmiastową odpowiedź na pytanie.
JimB,

3
Jestem wyraźnie świadomy, że się myliłem. Dwa błędy w jednym pytaniu. Możesz być pewien, że ich nie powtórzę.
Cronos87,

Odpowiedzi:


116

Gdybyś złapał błąd, zobaczyłbyś to:

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

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

Rzecz w tym, że nie możesz używać liczb całkowitych jako kluczy w JSON; to jest zabronione. Zamiast tego możesz wcześniej przekonwertować te wartości na ciągi, na przykład używając strconv.Itoa.

Więcej informacji znajdziesz w tym poście: https://stackoverflow.com/a/24284721/2679935


3
Tutaj możesz zobaczyć, jak mapują się typy: golang.org/pkg/encoding/json/#Unmarshal Zamiast tego możesz użyć wycinka, który będzie mapowany na tablicę JSON. Ponadto: zawsze sprawdzaj błędy;)
seong

2
Myślę, że zachowanie się zmieniło. Zobacz golang.org/pkg/encoding/json/#Unmarshal, aby dowiedzieć się, „Typ klucza mapy musi być ciągiem znaków, liczbą całkowitą lub implementacją kodowania.TextMarshaler”.
Ashhar Hasan

@AshharHasan Najwyraźniej zmieniło się to w Go 1.7 ( golang.org/doc/go1.7#encoding_json ), ale nadal nie robi tego, czego można się spodziewać: play.golang.org/p/0aFaQ_ByOk
julienc

czy istnieje sposób, aby to zrobić za pomocą mapy synchronizacji?
Shahrukh Mohammad

@ShahrukhMohammad Nie używałem Go od lat, nie będę w stanie odpowiedzieć na twoje pytanie ... Może spróbuj utworzyć nowe pytanie na SO!
julienc

27

W rzeczywistości mówi ci, co jest nie tak, ale zignorowałeś go, ponieważ nie sprawdziłeś błędu zwróconego przez json.Marshal.

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

Specyfikacja JSON nie obsługuje niczego poza ciągami znaków dla kluczy obiektów, podczas gdy javascript nie będzie tego wybredny, nadal jest nielegalny.

Masz dwie możliwości:

1 Użyj map[string]Fooi przekonwertuj indeks na łańcuch (na przykład używając fmt.Sprint):

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 Po prostu użyj wycinka (tablica 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
Masz rację. To wstydliwy błąd ... Naprawdę nie wiem, dlaczego użyłem int jako klucza JSON ... Dziękuję za przykłady.
Cronos87,

2

Ponieważ to pytanie zostało zadane / ostatnia odpowiedź, dodano obsługę typów kluczy innych niż łańcuchowe dla map dla json Marshal / UnMarshal poprzez użycie tutaj interfejsów TextMarshaler i TextUnmarshaler . Możesz po prostu zaimplementować te interfejsy dla swoich typów kluczy, a następnie działać zgodnie z oczekiwaniami.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)
}

Wynik:

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}]
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.