Это ожидаемый результат, который задокументирован в 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}