将Go的map转换为JSON。

huangapple go评论93阅读模式
英文:

Convert Go map to json

问题

我尝试使用encoding/json的Marshal函数将我的Go map转换为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}]

[]

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

英文:

I tried to convert my Go map to a json string with encoding/json Marshal, but it resulted in a empty string.

Here's my code :

package main

import (
	&quot;encoding/json&quot;
	&quot;fmt&quot;
)

type Foo struct {
	Number int    `json:&quot;number&quot;`
	Title  string `json:&quot;title&quot;`
}

func main() {
	datas := make(map[int]Foo)

	for i := 0; i &lt; 10; i++ {
		datas[i] = Foo{Number: 1, Title: &quot;test&quot;}
	}

	jsonString, _ := json.Marshal(datas)

	fmt.Println(datas)
	fmt.Println(jsonString)
}

My output is :

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

[]

I really don't know where I'm wrong. Thank you for your help.

答案1

得分: 161

如果你捕捉到了错误,你会看到这样的信息:

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

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

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

详细信息请参考这篇帖子:https://stackoverflow.com/a/24284721/2679935

英文:

If you had caught the error, you would have seen this:

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

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

The thing is you cannot use integers as keys in JSON; it is forbidden. Instead, you can convert these values to strings beforehand, for instance using strconv.Itoa.

See this post for more details: https://stackoverflow.com/a/24284721/2679935

答案2

得分: 32

实际上,它告诉你出了什么问题,但你忽略了它,因为你没有检查从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)
  1. 简单地使用切片(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)

播放示例

英文:

It actually tells you what's wrong, but you ignored it because you didn't check the error returned from json.Marshal.

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

JSON spec doesn't support anything except strings for object keys, while javascript won't be fussy about it, it's still illegal.

You have two options:

1 Use map[string]Foo and convert the index to string (using fmt.Sprint for example):

datas := make(map[string]Foo, N)

for i := 0; i &lt; 10; i++ {
	datas[fmt.Sprint(i)] = Foo{Number: 1, Title: &quot;test&quot;}
}
j, err := json.Marshal(datas)
fmt.Println(string(j), err)

2 Simply just use a slice (javascript array):

datas2 := make([]Foo, N)
for i := 0; i &lt; 10; i++ {
	datas2[i] = Foo{Number: 1, Title: &quot;test&quot;}
}
j, err = json.Marshal(datas2)
fmt.Println(string(j), err)

<kbd>playground</kbd>

答案3

得分: 5

这种行为随着时间的推移已经发生了变化。我正在使用go v1.16.5,并且我可以愉快地将int类型作为JSON键传递。我现在尝试了同样的问题,我可以看到以下结果。非字符串键的类型转换已经通过textMarshalertextUnmarshaler接口添加。有关更多信息,您可以访问此链接:https://golang.org/pkg/encoding/json/#Marshal

type Foo struct {
    Number int    `json:"number"`
    Title  string `json:"title"`
}

datas := make(map[int]Foo)

for i := 0; i < 5; i++ {
    datas[i] = Foo{Number: 1, Title: "test"}
}

jsonString, _ := json.Marshal(datas)

fmt.Println("Datasets Result:", datas)
fmt.Println("Marshal Datasets Result:", string(jsonString), err)

m := make(map[int]Foo)
err = json.Unmarshal(jsonString, &m)
if err != nil {
    panic(err)
}

fmt.Println("Unmarshal JSON Result:", m)

输出:

Datasets Result map: [0:{1 test} 1:{1 test} 2:{1 test} 3:{1 test} 4:{1 test}]

Marshal Datasets Result: {"0":{"number":1,"title":"test"},"1":{"number":1,"title":"test"},"2":{"number":1,"title":"test"},"3":{"number":1,"title":"test"},"4":{"number":1,"title":"test"}} <nil>

Unmarshal JSON Result: map[0:{1 test} 1:{1 test} 2:{1 test} 3:{1 test} 4:{1 test}]
英文:

This behaviour has been changed over time. I am using go v1.16.5 and I can happily pass int type in as JSON key. I have tried the same problem now and I can see the below result. Type conversion of a non-string key has been added by textMarshaler and textUnmarshaler interfaces. For more info, you can visit this https://golang.org/pkg/encoding/json/#Marshal

type Foo struct {
	Number int    `json:&quot;number&quot;`
	Title  string `json:&quot;title&quot;`
}

datas := make(map[int]Foo)

for i := 0; i &lt; 5; i++ {
	datas[i] = Foo{Number: 1, Title: &quot;test&quot;}
}

jsonString, _ := json.Marshal(datas)

fmt.Println(&quot;Datasets Result : &quot;, datas)
fmt.Println(&quot;Marshal Datasets Result : &quot;, string(jsonString), err)

m := make(map[int]Foo)
err = json.Unmarshal(jsonString, &amp;m)
if err != nil {
	panic(err)
}

fmt.Println(&quot;Unmarshal JSON Result : &quot;, m)

Output:

Datasets Result map : [0:{1 test} 1:{1 test} 2:{1 test} 3:{1 test} 4:{1 test}]

Marshal Datasets Result : {&quot;0&quot;:{&quot;number&quot;:1,&quot;title&quot;:&quot;test&quot;},&quot;1&quot;:{&quot;number&quot;:1,&quot;title&quot;:&quot;test&quot;},&quot;2&quot;:{&quot;number&quot;:1,&quot;title&quot;:&quot;test&quot;},&quot;3&quot;:{&quot;number&quot;:1,&quot;title&quot;:&quot;test&quot;},&quot;4&quot;:{&quot;number&quot;:1,&quot;title&quot;:&quot;test&quot;}} &lt;nil&gt;

Unmarshal JSON Result :  map[0:{1 test} 1:{1 test} 2:{1 test} 3:{1 test} 4:{1 test}]

答案4

得分: 4

自从提出/最后回答这个问题以来,通过使用TextMarshalerTextUnmarshaler接口,为JSON的Marshal/Unmarshal操作添加了对非字符串键类型的映射支持。你只需要为你的键类型实现这些接口,然后json.Marshal就会按预期工作。

package main

import (
	"encoding/json"
	"fmt"
	"strconv"
)

// Num 封装了int值,以便我们可以实现TextMarshaler和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}]
英文:

Since this question was asked/last answered, support for non string key types for maps for json Marshal/UnMarshal has been added through the use of TextMarshaler and TextUnmarshaler interfaces here. You could just implement these interfaces for your key types and then json.Marshal would work as expected.

package main
import (
&quot;encoding/json&quot;
&quot;fmt&quot;
&quot;strconv&quot;
)
// 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:&quot;number&quot;`
Title  string `json:&quot;title&quot;`
}
func main() {
datas := make(map[Num]Foo)
for i := 0; i &lt; 10; i++ {
datas[Num(i)] = Foo{Number: 1, Title: &quot;test&quot;}
}
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, &amp;m)
if err != nil {
panic(err)
}
fmt.Println(m)
}

Output:

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

答案5

得分: 3

data := map[string]interface{}
jsonByte, err := json.Marshal(data)
if err != nil{
log.Fatal(err)
}
jsonString := string(jsonByte)
fmt.Println(jsonString) // 将以 JSON 格式打印 data map。

英文:
data := map[string]interface{}
jsonByte, err := json.Marshal(data)
if err != nil{
log.Fatal(err)
}
jsonString := string(jsonByte)
fmt.Println(jsonString) // will be printing data map in json formate.

huangapple
  • 本文由 发表于 2014年7月9日 19:42:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/24652775.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定