型埋め込みを使用している構造体をjson.MarshalでJSON文字列に変換する際、意図しない挙動になるケースがあるので気を付ける。
下記のような構造体のインスタンスをjson.Marshalで文字列に変換する処理がある。
type Event struct {
ID int
time.Time // <- 埋め込みフィールド
}
event := Event{
ID: 1234,
Time: time.now(), // <- 構造体のインスタンス化時、埋め込みフィールドの名前は構造体の名前(=Time)
}
buf, _ := json.Marshal(event)
fmt.Println(string(str))
Event構造体をそのまま変換すると、以下のようなJSON文字列になることを期待しがち。
{"ID":1234,"Time":"2024-11-22T04::00:00.000000"}
しかし実際には、出力する文字列は以下のように現在時刻だけが出力される。
"2024-11-22T04::00:00.000000"
json.Marshalは対象の型がjson.Marshalerインタフェースを実装することでデフォルトのマーシャル動作を上書きすることが可能。
今回のケースではtime.Time型が時刻を返すMarshalJSONを実装しており、かつ、型埋め込みでプロモートされた結果、Event構造体のマーシャル動作が書き換わっていたのが原因だった。
回避策は以下の2つ
type Event struct {
ID int
Time time.Time // <- 名前を追加することでtime.Timeは埋め込み型でなくなる
}
func (e Event) MarshalJSON() ([]byte, error) {
return json.Marshal {
struct {
ID: int
Time time.Time
} {
ID: e.ID,
Time: e.Time,
}
}
}
富山在住のプログラマー。
フルリモートで働いています。
Categories
AWS
Cloudflare
Docker
Github
go
html
JavaScript
microCMS
MySQL
Monthly Archives
2024/12 (1)
2024/11 (3)
2024/10 (1)
2024/09 (3)
2024/08 (7)
2024/07 (7)
2024/06 (4)
2024/05 (5)
2024/04 (6)