Реализуйте json.Marshaler
в своей структуре, которая должна определить пользовательскую логику маршалинга, которая может удваивать поле DoubleMe
.
См. Этот пример:
type Message struct {
DoubleMe int `json:"double_me"`
Message string `json:"message"`
}
func (m Message) MarshalJSON() ([]byte, error) {
m.DoubleMe *= 2
type Message2 Message
return json.Marshal(Message2(m))
}
func main() {
m := Message{5, "Hello, World!"}
data, err := json.Marshal(m)
fmt.Println(string(data), err)
fmt.Println("Original:", m)
}
Вывод (попробуйте на Go Playground ):
{"double_me":10,"message":"Hello, World!"} <nil>
Original: {5 Hello, World!}
Некоторые примечания:
Если вам нужно, чтобы это работалотакже в обратном направлении (например, при демаршалинге, разделите значение на 2), также реализуйте json.Unmarshaler
(оставлено читателю в качестве упражнения).
Даже если мыудвоил поле, после маршалинга исходное значение не изменилось.Это связано с тем, что метод имеет получатель без указателя, поэтому внутри метода получается и изменяется только копия, но не исходное значение.Если бы мы использовали приемник указателя, нам пришлось бы позаботиться о его восстановлении.
Также обратите внимание, что новый тип Message2
создается и используется внутри метода MarshalJSON()
,Это потому, что мы также использовали пакет json
для выполнения «обычного» маршалинга после того, как применили нашу собственную логику.Но если мы передадим m
в json.Marshal()
, это будет бесконечная «рекурсия», потому что пакет json
снова вызовет этот метод MarshalJSON()
.Вместо этого мы создали тип Message2
с базовым типом Message
.Это означает, что Message2
имеет нулевые методы (он не реализует json.Marshaler
), поэтому передача значения Message2
в json.Marshal()
больше не будет вызывать этот метод, и, поскольку он имеет Message
в качестве базового типа, мыможно просто преобразовать значение типа Message
в Message2
.