Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 10862] ファイルの概要

このコミットは、Go言語の標準ライブラリである encoding/json パッケージに、json.Marshal および json.Unmarshal 関数の使用例を示す example_test.go ファイルを追加するものです。この新しいファイルは、encoding/json パッケージのドキュメントとテストスイートの一部として機能し、開発者がこれらのJSONエンコーディング/デコーディング機能をどのように利用できるかを具体的に示します。

コミット

encoding/json: examples for Marshal and Unmarshal

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5493075

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/5ede9df5a0905e79a1ed8d2be75d6c4f2e7a1787

元コミット内容

encoding/json: examples for Marshal and Unmarshal

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5493075

変更の背景

このコミットの背景には、Go言語の標準ライブラリのドキュメンテーションと使いやすさの向上という目的があります。encoding/json パッケージは、GoアプリケーションでJSONデータを扱う上で非常に重要なコンポーネントですが、その利用方法を具体的に示すコード例が不足している場合がありました。

Go言語のテストフレームワークでは、_test.go ファイル内に Example 関数を記述することで、その関数の出力がドキュメントとして自動生成され、かつテストの一部として実行されるというユニークな機能があります。これにより、コード例が常に最新かつ正確であることが保証されます。

json.Marshaljson.Unmarshal は、Goの構造体とJSONデータの間の変換を行うための中心的な関数です。これらの関数の具体的な使用例を提供することで、以下のようなメリットが生まれます。

  1. 学習コストの削減: 新しい開発者が encoding/json パッケージを使い始める際に、具体的なコード例を見ることで、どのように構造体を定義し、JSONとの間でデータをやり取りするのかを素早く理解できます。
  2. ドキュメントの充実: go doc コマンドや pkg.go.dev などの公式ドキュメントサイトで、これらの例が直接表示されるようになり、ドキュメントの質が向上します。
  3. 正確性の保証: Example 関数は通常のテストと同様に実行されるため、コード例がコンパイルエラーを起こしたり、期待通りの出力を生成しなかったりするリスクが低減されます。これにより、ドキュメントと実際のコードの乖離を防ぎます。

このコミットは、Go言語の標準ライブラリが提供する機能の利用を促進し、開発者の生産性を向上させるための、典型的なドキュメンテーション改善の一環と言えます。

前提知識の解説

Go言語の encoding/json パッケージ

encoding/json パッケージは、Go言語でJSON (JavaScript Object Notation) データをエンコード(Goのデータ構造からJSONへ)およびデコード(JSONからGoのデータ構造へ)するための機能を提供します。主な関数は以下の通りです。

  • json.Marshal(v interface{}) ([]byte, error): Goの任意のデータ構造 v をJSON形式のバイトスライスにエンコードします。構造体のフィールドは、エクスポート可能(先頭が大文字)である必要があり、JSONフィールド名として使用されます。json タグ(例: json:"field_name")を使用して、JSONフィールド名をカスタマイズしたり、フィールドを無視したりすることもできます。
  • json.Unmarshal(data []byte, v interface{}) error: JSON形式のバイトスライス data をGoのデータ構造 v にデコードします。v はポインタである必要があります。Marshal と同様に、構造体のフィールド名や json タグがデコードの際に利用されます。

Go言語の _test.go ファイルと Example 関数

Go言語では、テストコードは通常、テスト対象のソースファイルと同じディレクトリに _test.go というサフィックスを持つファイルとして配置されます。これらのファイルは go test コマンドによって自動的に検出され、実行されます。

_test.go ファイル内で定義できる特別な関数の一つに Example 関数があります。Example 関数は、以下のような特徴を持ちます。

  • 命名規則: Example で始まり、その後にテスト対象の関数名や型名が続く(例: ExampleMarshalExampleUnmarshal)。
  • 出力の検証: Example 関数内で fmt.Printos.Stdout.Write などを使って標準出力に出力された内容は、関数のコメントに記述された Output: ブロックと比較されます。一致しない場合、テストは失敗します。
  • ドキュメント生成: Example 関数は、go doc コマンドや公式ドキュメントサイト(pkg.go.dev)で、対応する関数や型の使用例として自動的に表示されます。これにより、コード例がドキュメントの一部となります。

このメカニズムは、Goのドキュメンテーションが常に最新かつ実行可能なコード例を含むことを保証するための強力な機能です。

Go言語の構造体 (Struct)

Go言語の構造体は、異なる型のフィールドをまとめた複合データ型です。オブジェクト指向プログラミングにおけるクラスの軽量版と考えることができます。構造体は、関連するデータを一つの単位として扱うために使用されます。

例:

type Person struct {
    Name string
    Age  int
}

この Person 構造体は、Name (文字列) と Age (整数) という2つのフィールドを持ちます。JSONエンコーディング/デコーディングの際には、これらのフィールド名(または json タグで指定された名前)がJSONのキーとして使用されます。

技術的詳細

このコミットで追加される example_test.go ファイルには、encoding/json パッケージの MarshalUnmarshal 関数の具体的な使用例がそれぞれ一つずつ含まれています。

ExampleMarshal 関数

この関数は、Goの構造体をJSON形式のバイトスライスにエンコードする json.Marshal の使用例を示します。

  1. ColorGroup 構造体の定義:

    type ColorGroup struct {
        ID     int
        Name   string
        Colors []string
    }
    

    ID (整数)、Name (文字列)、Colors (文字列のスライス) という3つのフィールドを持つ構造体が定義されています。これらのフィールドはすべてエクスポート可能(先頭が大文字)であるため、json.Marshal によってJSONに変換されます。

  2. ColorGroup インスタンスの作成:

    group := ColorGroup{
        ID:     1,
        Name:   "Reds",
        Colors: []string{"Crimson", "Red", "Ruby", "Maroon"},
    }
    

    ID が1、Name が"Reds"、Colors が複数の赤系の色を含むスライスである ColorGroup のインスタンスが初期化されます。

  3. json.Marshal の呼び出し:

    b, err := json.Marshal(group)
    

    group インスタンスが json.Marshal に渡され、JSON形式のバイトスライス b とエラー err が返されます。

  4. エラーハンドリングと出力:

    if err != nil {
        fmt.Println("error:", err)
    }
    os.Stdout.Write(b)
    

    エラーが発生した場合は標準エラーに出力し、成功した場合は b (JSONバイトスライス) を標準出力に書き出します。

  5. 期待される出力:

    // {"ID":1,"Name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]}
    

    コメントとして、この ExampleMarshal 関数が実行された際に標準出力に書き出されるJSON文字列が示されています。これは、go test がこの例を検証するために使用するものです。

ExampleUnmarshal 関数

この関数は、JSON形式のバイトスライスをGoの構造体のスライスにデコードする json.Unmarshal の使用例を示します。

  1. JSONデータの定義:

    var jsonBlob = []byte(`[
        {"Name": "Platypus", "Order": "Monotremata"},
        {"Name": "Quoll",    "Order": "Dasyuromorphia"}
    ]`)
    

    2つの動物の情報をJSON配列として含むバイトスライス jsonBlob が定義されています。

  2. Animal 構造体の定義:

    type Animal struct {
        Name  string
        Order string
    }
    

    Name (文字列) と Order (文字列) という2つのフィールドを持つ構造体が定義されています。

  3. デコード先の変数の宣言:

    var animals []Animal
    

    Animal 構造体のスライス animals が宣言されます。json.Unmarshal はこのスライスにデコードされたデータを格納します。

  4. json.Unmarshal の呼び出し:

    err := json.Unmarshal(jsonBlob, &animals)
    

    jsonBlobanimals のアドレス(ポインタ)が json.Unmarshal に渡されます。UnmarshaljsonBlob の内容を解析し、animals スライスに Animal 構造体のインスタンスとしてデータを格納します。

  5. エラーハンドリングと出力:

    if err != nil {
        fmt.Println("error:", err)
    }
    fmt.Printf("%+v", animals)
    

    エラーが発生した場合は標準エラーに出力し、成功した場合は animals スライスの内容を %+v フォーマット(構造体のフィールド名と値を含む詳細な形式)で標準出力に書き出します。

  6. 期待される出力:

    // [{Name:Platypus Order:Monotremata} {Name:Quoll Order:Dasyuromorphia}]
    

    コメントとして、この ExampleUnmarshal 関数が実行された際に標準出力に書き出されるGoのデータ構造の文字列表現が示されています。

これらの例は、encoding/json パッケージの基本的な使い方を明確かつ簡潔に示しており、Goの構造体とJSONデータ間のマッピングの仕組みを理解する上で非常に役立ちます。

コアとなるコードの変更箇所

このコミットでは、src/pkg/encoding/json/example_test.go という新しいファイルが追加されています。既存のファイルへの変更はありません。

diff --git a/src/pkg/encoding/json/example_test.go b/src/pkg/encoding/json/example_test.go
new file mode 100644
index 0000000000..7f4a78c315
--- /dev/null
+++ b/src/pkg/encoding/json/example_test.go
@@ -0,0 +1,48 @@
+// Copyright 2011 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json_test
+
+import (
+	"encoding/json"
+	"fmt"
+	"os"
+)
+
+// {"ID":1,"Name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]}
+func ExampleMarshal() {
+	type ColorGroup struct {
+		ID     int
+		Name   string
+		Colors []string
+	}
+	group := ColorGroup{
+		ID:     1,
+		Name:   "Reds",
+		Colors: []string{"Crimson", "Red", "Ruby", "Maroon"},
+	}
+	b, err := json.Marshal(group)
+	if err != nil {
+		fmt.Println("error:", err)
+	}
+	os.Stdout.Write(b)
+}
+
+// [{Name:Platypus Order:Monotremata} {Name:Quoll Order:Dasyuromorphia}]
+func ExampleUnmarshal() {
+	var jsonBlob = []byte(`[
+		{"Name": "Platypus", "Order": "Monotremata"},
+		{"Name": "Quoll",    "Order": "Dasyuromorphia"}
+	]`)
+	type Animal struct {
+		Name  string
+		Order string
+	}
+	var animals []Animal
+	err := json.Unmarshal(jsonBlob, &animals)
+	if err != nil {
+		fmt.Println("error:", err)
+	}
+	fmt.Printf("%+v", animals)
+}

コアとなるコードの解説

追加された src/pkg/encoding/json/example_test.go ファイルは、json_test パッケージに属しています。これは、encoding/json パッケージの内部テストではなく、外部からパッケージを利用する際の挙動をテスト・例示するための慣習的な方法です。

ファイルの内容は以下の通りです。

  1. 著作権表示:

    // Copyright 2011 The Go Authors.  All rights reserved.
    // Use of this source code is governed by a BSD-style
    // license that can be found in the LICENSE file.
    

    Goプロジェクトの標準的な著作権ヘッダーです。

  2. パッケージ宣言:

    package json_test
    

    encoding/json パッケージのテストパッケージであることを示します。_test サフィックスは、このパッケージがテスト専用であり、メインのパッケージとは別の名前空間を持つことを意味します。これにより、テストコードがパッケージの内部実装に依存しすぎることなく、公開APIのみを使用してテストを行うことができます。

  3. インポート:

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

    encoding/json パッケージ自体、標準出力へのフォーマット済み出力のための fmt パッケージ、および標準出力へのバイトスライス書き込みのための os パッケージがインポートされています。

  4. ExampleMarshal 関数: 前述の「技術的詳細」セクションで詳しく解説した通り、ColorGroup 構造体を定義し、そのインスタンスを json.Marshal でJSONにエンコードし、結果を標準出力に書き出す例です。関数の直前のコメント行 // {"ID":1,"Name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]} は、この例の期待される出力であり、go test によって検証されます。

  5. ExampleUnmarshal 関数: 前述の「技術的詳細」セクションで詳しく解説した通り、JSON形式のバイトスライス jsonBlob を定義し、Animal 構造体のスライスに json.Unmarshal でデコードし、結果を fmt.Printf で標準出力に書き出す例です。関数の直前のコメント行 // [{Name:Platypus Order:Monotremata} {Name:Quoll Order:Dasyuromorphia}] は、この例の期待される出力であり、go test によって検証されます。

このファイル全体が、encoding/json パッケージの基本的なJSONエンコーディング/デコーディング機能の利用方法を、実行可能で検証可能な形で提供しています。

関連リンク

  • Gerrit Change-ID: https://golang.org/cl/5493075 このリンクは、Goプロジェクトがコードレビューに利用しているGerritシステムにおける、このコミットに対応する変更セット(Change-ID)を示しています。Gerritのページでは、コミットの詳細、レビューコメント、関連するパッチセットの履歴などを確認できます。

参考にした情報源リンク