NullableなJSONフィールドのGoポインタ表現

GoのNullableなJSONフィールドにポインタ型(*string, *int)を使う理由とタイミングを学びます。nilとゼロ値のセマンティクスを解説。

Advanced Types

詳細な説明

NullableなJSONフィールドにポインタを使う

JSONは値として null をサポートしていますが、Goにはプリミティブのnull型がありません。解決策はポインタ型を使用することで、nil がJSON null を表します。

問題点

{ "name": "Alice", "age": null, "score": 0 }

通常の int フィールドでは、null0 の両方が 0 にアンマーシャリングされ、区別できなくなります。

解決策:ポインタ

type Player struct {
    Name  string `json:"name"`
    Age   *int   `json:"age"`
    Score *int   `json:"score"`
}

これにより:

  • nullAgenil
  • 0Score は値 0int を指す
  • キーが欠落 → Agenil

ポインタフィールドの確認

if player.Age != nil {
    fmt.Printf("Age: %d\n", *player.Age)
} else {
    fmt.Println("Age: not provided")
}

ポインタを使うべき場面

以下の場合にポインタを使用します:

  • APIがフィールドに null を送信し、それがゼロ値と異なる場合
  • 「フィールドが存在しない」と「フィールドがゼロ」を区別する必要がある場合
  • 変更されたフィールドのみ送信するPATCHリクエストボディの構築時

以下の場合はポインタを避けます:

  • フィールドが常に存在し、非nullの場合
  • ゼロ値がドメインで有効な値でない場合
  • null安全性よりもシンプルさが重要な場合

omitemptyとの組み合わせ

Age *int `json:"age,omitempty"`

ポインタがnilの場合はフィールドを省略し、非nil(0 であっても)の場合は含めます。

パフォーマンスに関する注意

ポインタはフィールドごとに小さなヒープアロケーションを追加します。数百万のオブジェクトを処理する高スループットサービスでは、不必要なポインタの回避がパフォーマンスを向上させる場合があります。

ユースケース

データベースバックのAPIは、値のないカラムに対してnullを返すことが多いです。Go構造体でポインタフィールドを使用することで、年齢を0に設定したユーザーと設定していないユーザーを区別できます。

試してみる — JSON to Go Struct Converter

フルツールを開く