Не могу понять странного поведения кастомного маршала 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 := []Int{100, 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
Что мне не хватает?

Это ожидаемый результат, который задокументирован в json.Marshal():
Map values encode as JSON objects. The map's key type must either be a string, an integer type, or implement encoding.TextMarshaler. The map keys are sorted and used as JSON object keys by applying the following rules, subject to the UTF-8 coercion described for string values above:
- 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!)
При этом вывод будет (попробуйте на Перейти на игровую площадку):
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
}
На этот раз вывод будет (попробуйте на Перейти на игровую площадку):
array ["100-1","200-2"] <nil>
map wtf? {"100-10":true,"200-20":true} <nil>
map must be: {"100-10":true, "200-20":true}