Go1.24で追加されるomitzeroについて

2024/12/22に公開

はじめに

皆さんどうも! しろね ✨ です。
さて、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 an IsZero() 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 both omitempty and omitzero are specified, the field will be omitted if the value is either empty or zero (or both).

意訳するとこんな感じです。(僕なりの翻訳なので間違ってる可能性あり)

omitzeroというタグが新たに追加されました。このオプションは値がゼロのときにフィールドを json から省略します。フィールドがIsZero() boolメソッドを持っていた場合は、値がゼロであるかを確かめるために使用され、それ以外の場合は各型のゼロ値だった場合にゼロだと判断されます。 omitemptyomitzero が両方指定されていた場合、値がゼロ、空もしくはその両方だった場合にフィールドが省略されます。

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を追加するプロポーサル中にそれらしき定義が述べられていました。

  1. Lets start by agreeing on a definition for empty vs zero, here is my proposal:
  • empty JSON-values: false0""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 タグについて説明させてもらいました!誰かの参考になったのなら幸いです。
では!

参考

https://tip.golang.org/doc/go1.24
https://github.com/golang/go/issues/45669

GitHubで編集を提案

Discussion