omitempty を超えて：Go 1.24 における omitzero の理解

[![表紙](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967563/7d9ca1f3-a792-4c28-b682-9e0c45d31fae.png)](https://leapcell.io/?lc_t=q_goomitzero)

## 前書き

Go 1.24 バージョンでは、`encoding/json` パッケージに `omitzero` タグが新たに追加され、ゼロ値フィールドの無視に関する動作がより明確かつカスタマイズ可能になりました。この記事では、`omitzero` タグの使用方法について詳しく解説します。

## omitzero タグ

`omitzero` タグは、Go オブジェクトを JSON にシリアライズする際に、どのゼロ値フィールドを無視するかを制御するために使用されます。`omitempty` タグとは異なり、`omitempty` は空値（empty value）を無視します。一方で、ゼロ値（zero value）と空値は似ているようで、Go においては同一ではありません。例えば：

- `time.Time` 型の場合、ゼロ値は `"0001-01-01T00:00:00Z"` であり、これは空値とは見なされません。
- スライスフィールド `IntSlice []int` においては、値が `[]` または `nil` の場合、どちらも空値と見なされます。

### なぜ omitzero を使うのか

- **精密な制御**：空値ではなく、明確にゼロ値フィールドを無視できます。
- **カスタマイズ可能な制御**：`IsZero() bool` メソッドを使用することで、フィールドのゼロ値の判定ロジックをカスタマイズできます。

## omitzero タグの使用方法

```go
package main

import (
  "encoding/json"
  "fmt"
  "time"
)

type User struct {
  Name    string    `json:"name,omitzero"`
  Age     int       `json:"age,omitzero"`
  Hobbies []string  `json:"hobbies,omitzero"`
  BornAt  time.Time `json:"born_at,omitzero"`
}

func main() {
  user := User{
    Name:    "Leapcell",
    Age:     18,
    Hobbies: []string{},
  }

  bytes, _ := json.MarshalIndent(user, "", "  ")
  fmt.Println(string(bytes))
}
```

`string(bytes)` を出力すると、以下のような JSON 結果になります：

```json
{
  "name": "Leapcell",
  "age": 18,
  "hobbies": []
}
```

もし `omitempty` タグを使用した場合、`hobbies` フィールドは省略されます。しかし、たとえ `born_at` がゼロ値であっても、`"born_at": "0001-01-01T00:00:00Z"` のようにシリアライズされます。`omitzero` タグを使用することで、どのフィールドが無視されるかをより正確に制御でき、ゼロ値フィールドのみを除外することが可能になります。

## IsZero() bool メソッド

`IsZero() bool` メソッドは、フィールドのゼロ値を判断するロジックをカスタマイズするために使われます。あるフィールドのゼロ値の判定方法を変更したい場合、そのフィールドに対して `IsZero` メソッドを実装することができます。以下はその一例です：

```go
package main

import (
  "encoding/json"
  "fmt"
  "time"
)

type Age int

func (age *Age) IsZero() bool {
  return *age <= 0
}

type User struct {
  Name    string    `json:"name,omitzero"`
  Age     Age       `json:"age,omitzero"`
  Hobbies []string  `json:"hobbies,omitzero"`
  BornAt  time.Time `json:"born_at,omitzero"`
}

func main() {
  user := User{
    Name:    "Leapcell",
    Age:     -1,
    Hobbies: []string{},
  }

  bytes, _ := json.MarshalIndent(user, "", "  ")
  fmt.Println(string(bytes))
}
```

この例では、`Age` フィールドは `IsZero` メソッドを実装しており、ゼロ値の判定ロジックを制御しています。もし `Age` が 0 以下であれば、`IsZero` は `true` を返し、そのフィールドは無視されます。出力結果は以下の通りです：

```json
{
  "name": "Leapcell",
  "hobbies": []
}
```

## まとめ

Go 言語において、`omitzero` タグを使用することで、無視されるフィールドを精密に制御することができ、ゼロ値フィールドのみを除外することが可能になります。また、`IsZero` メソッドを実装することにより、フィールドごとにゼロ値の判定ロジックをカスタマイズでき、様々なシリアライズ要件に対応することができます。

---

### [私たちはLeapcell、Goプロジェクトのホスティングの最適解です。](https://leapcell.io/?lc_t=q_goomitzero)

[![Leapcell](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967563/8cd6e3c9-1bfe-42dd-915c-ba6479463d8f.png)](https://leapcell.io/?lc_t=q_goomitzero)

[Leapcell](https://leapcell.io/?lc_t=q_goomitzero)は、Webホスティング、非同期タスク、Redis向けの次世代サーバーレスプラットフォームです：

**複数言語サポート**

- Node.js、Python、Go、Rustで開発できます。

**無制限のプロジェクトデプロイ**

- 使用量に応じて料金を支払い、リクエストがなければ料金は発生しません。

**比類のないコスト効率**

- 使用量に応じた支払い、アイドル時間は課金されません。
- 例: $25で6.94Mリクエスト、平均応答時間60ms。

**洗練された開発者体験**

- 直感的なUIで簡単に設定できます。
- 完全自動化されたCI/CDパイプラインとGitOps統合。
- 実行可能なインサイトのためのリアルタイムのメトリクスとログ。

**簡単なスケーラビリティと高パフォーマンス**

- 高い同時実行性を容易に処理するためのオートスケーリング。
- ゼロ運用オーバーヘッド — 構築に集中できます。

[ドキュメントで詳細を確認！](https://docs.leapcell.io/)

[![Try Leapcell](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967563/31aa912a-617b-438c-bfde-8f0e5423958e.png)](https://leapcell.io/?lc_t=q_goomitzero)

Xでフォローする：[@LeapcellHQ](https://x.com/LeapcellHQ)

---

[ブログでこの記事を読む](https://leapcell.io/blog/go-124-omitzero-tag-explained)