Go1.24で追加されるomitzeroについて
はじめに
皆さんどうも! しろね ✨ です。
さて、12 月に入り 2025 年が見え始めてきましたがこのタイミングでGo1.24rc1が公開されました!
Go1.24 ではtype alias での型パラメータのサポートと go.mod
で依存ツールのバージョン管理が可能になるという 2 点が更新の目玉ですがRelease Noteを覗いているとそれ以外にも面白そうな更新がいくつか加えられているのがわかります。
今回はその中でもencoding/json
に新しく追加されるomitzero
タグについて書いていこうと思います。
Release Note をとりあえず読む
最初に Release Note にどのように書かれているかを読んでみようと思います。
When marshaling, a struct field with the new
omitzero
option in the struct field tag will be omitted if its value is zero. If the field type has anIsZero() bool
method, that will be used to determine whether the value is zero. Otherwise, the value is zero if it is the zero value for its type.
If bothomitempty
andomitzero
are specified, the field will be omitted if the value is either empty or zero (or both).
意訳するとこんな感じです。(僕なりの翻訳なので間違ってる可能性あり)
omitzero
というタグが新たに追加されました。このオプションは値がゼロのときにフィールドを json から省略します。フィールドがIsZero() bool
メソッドを持っていた場合は、値がゼロであるかを確かめるために使用され、それ以外の場合は各型のゼロ値だった場合にゼロだと判断されます。omitempty
とomitzero
が両方指定されていた場合、値がゼロ、空もしくはその両方だった場合にフィールドが省略されます。
jsonへの変換方法を指定できる構造体タグにomitzero
が増えるみたいですね!
追加された背景
プロポーサルでは、ネストした構造体を json に変換する際に omitempty
では混乱する場面があると述べられています。というのもomitempty
は構造体がnil
でないと json への変換時に省略しません。つまり
type Foo struct {
EmptyStruct struct{} `json:",omitempty"`
}
このような構造体があった際に、これを変換すると
{ "emptystruct": {} }
という json が出力されてしまうのです。
また、Go で時間を表すときには一般に time.Time
構造体を使用すると思いますが time.Time
構造体のゼロ値は少し特殊なものとなっており直感的ではないです。そのため、ほか言語などで混乱を引き起こさないためにも json に変換する際にゼロだった場合は省略したいというのがプロポーサルで述べられていた理由です。
ゼロと空の違い is 何?
Release Note を読んだだけだとゼロと空の区別がつかないと思います。その答えは、omitzero
を追加するプロポーサル中にそれらしき定義が述べられていました。
- Lets start by agreeing on a definition for empty vs zero, here is my proposal:
- empty JSON-values:
false
,0
,""
,null
,[]
,{}
- zero JSON-values: empty JSON-values and objects containing only empty JSON-values eg.
{a: null, b: 0}
プリミティブ型の場合はゼロも空も同一です。構造体の場合は構造体がnil
ならば空、中のフィールドがすべてゼロなら構造体もゼロとなります。
実際に使ってみる
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string
Age int
Pet Pet `json:",omitempty,omitzero"`
}
type Pet struct {
Name string
Age int
}
func displayJsonFormat(person *Person) {
b, err := json.Marshal(person)
if err != nil {
panic(err)
}
fmt.Printf("%s\n", string(b))
}
func main() {
person := &Person{
Name: "John",
Age: 30,
Pet: Pet{Name: "Max", Age: 5},
}
displayJsonFormat(person)
person = &Person{
Name: "John",
Age: 30,
Pet: Pet{},
}
displayJsonFormat(person)
}
❯ go1.24rc1 run main.go
{"Name":"John","Age":30,"Pet":{"Name":"Max","Age":5}}
{"Name":"John","Age":30}
簡単に動かしてみるとこのような感じできちんと省略されているのが解ると思います。
まとめ
今回は Go1.24 で追加されるomitzero
タグについて説明させてもらいました!誰かの参考になったのなら幸いです。
では!
参考
Discussion