如何在 JSON 中自定义编组映射键
Posted
技术标签:
【中文标题】如何在 JSON 中自定义编组映射键【英文标题】:How to custom marshal map keys in JSON 【发布时间】:2019-02-09 04:58:58 【问题描述】:我无法理解自定义元帅 int
到 string
的奇怪行为。
这是一个例子:
package main
import (
"encoding/json"
"fmt"
)
type Int int
func (a Int) MarshalJSON() ([]byte, error)
test := a / 10
return json.Marshal(fmt.Sprintf("%d-%d", a, test))
func main()
array := []Int100, 200
arrayJson, _ := json.Marshal(array)
fmt.Println("array", string(arrayJson))
maps := map[Int]bool
100: true,
200: true,
mapsJson, _ := json.Marshal(maps)
fmt.Println("map wtf?", string(mapsJson))
fmt.Println("map must be:", `"100-10":true, "200-20":true`)
输出是:
array ["100-10","200-20"]
map wtf? "100":true,"200":true
map must be: "100-10":true, "200-20":true
https://play.golang.org/p/iiUyL2Hc5h_P
我错过了什么?
【问题讨论】:
【参考方案1】:这是预期的结果,记录在json.Marshal()
:
地图值编码为 JSON 对象。映射的键类型必须是字符串、整数类型,或者实现 encoding.TextMarshaler。通过应用以下规则对映射键进行排序并用作 JSON 对象键,但要遵守上面为字符串值描述的 UTF-8 强制:
- string keys are used directly - encoding.TextMarshalers are marshaled - integer keys are converted to strings
请注意,映射键与属性值的处理方式不同,因为 JSON 中的映射键是属性名称,始终为 string
值(而属性值可能是 JSON 文本、数字和布尔值)。
根据文档,如果您希望它也适用于地图键,请实现 encoding.TextMarshaler
:
func (a Int) MarshalText() (text []byte, err error)
test := a / 10
return []byte(fmt.Sprintf("%d-%d", a, test)), nil
(请注意,MarshalText()
应该返回“只是”简单文本,而不是 JSON 文本,因此我们在其中省略了 JSON 编组!)
这样,输出将是(在Go Playground 上尝试):
array ["100-10","200-20"] <nil>
map wtf? "100-10":true,"200-20":true <nil>
map must be: "100-10":true, "200-20":true
请注意,encoding.TextMarshaler
就足够了,因为在编组为值时也会检查它,而不仅仅是映射键。所以你不必同时实现encoding.TextMarshaler
和json.Marshaler
。
如果你同时实现了这两个,当值被封送为“简单”值和映射键时,你可以有不同的输出,因为json.Marshaler
在生成值时优先:
func (a Int) MarshalJSON() ([]byte, error)
test := a / 100
return json.Marshal(fmt.Sprintf("%d-%d", a, test))
func (a Int) MarshalText() (text []byte, err error)
test := a / 10
return []byte(fmt.Sprintf("%d-%d", a, test)), nil
这次的输出将是(在Go Playground上试试):
array ["100-1","200-2"] <nil>
map wtf? "100-10":true,"200-20":true <nil>
map must be: "100-10":true, "200-20":true
【讨论】:
以上是关于如何在 JSON 中自定义编组映射键的主要内容,如果未能解决你的问题,请参考以下文章
如何在杰克逊序列化中自定义日期,@JsonSerialize 不起作用
Steam优化Xbox手柄体验 支持绑定背键及分享键自定义设置