将Go map转换为json


94

我试图用encoding/jsonMarshal 将Go映射转换为json字符串,但结果为空字符串。

这是我的代码:

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

我的输出是:

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

[]

我真的不知道我在哪里错。谢谢您的帮助。


30
请不要在未发表评论的情况下投票。我认为这个问题是一个好问题(+1):它包含所有代码,包含一个精确的问题,输出... ...完全是主题,OP付出了很多努力来提出一个好问题。在这里放下选票真是太可惜了!
topskip 2014年

4
该问题的确源于OP明确地忽略了将立即回答该问题的错误。
JimB

3
我很尽责,我错了。一个问题有两个错误。您可以确定我不会重复它们。
Cronos87

Answers:


110

如果发现错误,您将看到以下内容:

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

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

问题是您不能在JSON中使用整数作为键;这是被禁止的。相反,您可以预先将这些值转换为字符串,例如使用strconv.Itoa

请参阅此帖子以获取更多详细信息:https : //stackoverflow.com/a/24284721/2679935


3
在这里,您可以看到类型的映射方式:golang.org/pkg/encoding/json/#Unmarshal 您可以改用切片,该切片将映射到JSON数组。另外:请务必检查错误;)
2014年

2
我想行为已经改变。请参阅golang.org/pkg/encoding/json/#Unmarshal以获取“地图的键类型必须为字符串,整数类型或实现encoding.TextMarshaler。”
Ashhar Hasan

@AshharHasan显然,它在Go 1.7(改变golang.org/doc/go1.7#encoding_json),但它仍然不会做你所期望的:play.golang.org/p/0aFaQ_ByOk
julienc

有没有办法做到这一点与sync.Map?
沙鲁克·穆罕默德

@ShahrukhMohammad我已经好几年没有使用Go了,我将无法回答您的问题……也许尝试在SO上创建一个新问题!
julienc

27

它实际上告诉您出了什么问题,但是您忽略了它,因为您没有检查从返回的错误json.Marshal

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

JSON规范不支持除对象键字符串以外的任何内容,尽管javascript对此并不挑剔,但它仍然是非法的。

您有两种选择:

1使用map[string]Foo并将索引转换为字符串(例如使用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只需使用一个切片(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
你是对的。这是一个可耻的错误...我真的不知道为什么我将int用作json键...谢谢您的示例。
Cronos87

2

自从问到/最后回答这个问题以来,已通过使用此处TextMarshalerTextUnmarshaler接口添加了对JSON Marshal / UnMarshal映射的非字符串键类型的支持。您可以只为您的键类型实现这些接口,然后即可按预期工作。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)
}

输出:

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}]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.