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

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

このコミットは、Go言語の標準ライブラリにencodingパッケージを新規追加するものです。このパッケージは、バイナリ形式およびテキスト形式のデータ変換(エンコーディング/デコーディング)を行うための共通インターフェースを定義します。これにより、encoding/gobencoding/jsonencoding/xmlといった既存のエンコーディングパッケージが、これらの共通インターフェースを実装する型を統一的に扱えるようになります。

コミット

commit 48b90bbc55889ab12239ef0b3c884316d8f31b1b
Author: Russ Cox <rsc@golang.org>
Date:   Wed Aug 14 00:18:20 2013 -0400

    encoding: new package
    
    See golang.org/s/go12encoding for design.
    
    R=r
    CC=golang-dev
    https://golang.org/cl/12541051

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

https://github.com/golang/go/commit/48b90bbc55889ab12239ef0b3c884316d8f31b1b

元コミット内容

encoding: new package

See golang.org/s/go12encoding for design.

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

変更の背景

このコミットの背景には、Go言語のエンコーディング関連パッケージ(encoding/json, encoding/gob, encoding/xmlなど)における型の扱いを標準化し、より柔軟で再利用可能な設計を実現するという目的があります。

Go 1.2のリリースに向けて、time.Time型のような標準的な型が、様々なエンコーディング形式で適切にシリアライズ・デシリアライズされる必要がありました。しかし、各エンコーディングパッケージがそれぞれ独自のインターフェースやメカニズムで型を処理していると、型の開発者は各エンコーディングパッケージごとに個別のロジックを実装する必要が生じ、コードの重複や保守性の低下を招きます。

golang.org/s/go12encodingで提案された設計では、TextMarshalerBinaryMarshalerといった共通のインターフェースを導入することで、この問題を解決しようとしました。これらのインターフェースを型が実装することで、その型はどのエンコーディングパッケージからでも、そのインターフェースを通じて統一的にエンコード・デコードされることが期待されます。これにより、例えばtime.Time型が一度TextMarshalerを実装すれば、encoding/jsonでもencoding/xmlでも、その実装に基づいてテキスト形式に変換されるようになります。

この新しいencodingパッケージは、これらの共通インターフェースを一箇所に集約し、Goの標準ライブラリ全体でエンコーディングの振る舞いを一貫させるための基盤を提供します。

前提知識の解説

  • エンコーディングとデコーディング:

    • エンコーディング(符号化): ある形式のデータを別の形式に変換するプロセスです。例えば、Goの構造体をJSON文字列に変換したり、バイナリデータをBase64文字列に変換したりすることです。
    • デコーディング(復号化): エンコーディングされたデータを元の形式に戻すプロセスです。JSON文字列をGoの構造体に戻したり、Base64文字列をバイナリデータに戻したりすることです。
    • プログラミングにおいては、データの永続化(ファイル保存、データベース保存)、ネットワーク転送、異なるシステム間でのデータ交換など、様々な場面でエンコーディングとデコーディングが不可欠です。
  • Go言語のインターフェース:

    • Go言語のインターフェースは、メソッドのシグネチャの集合を定義する型です。
    • ある型がインターフェースで定義されたすべてのメソッドを実装している場合、その型はそのインターフェースを「実装している」とみなされます。明示的な宣言は不要です(ダックタイピング)。
    • インターフェースは、異なる具体的な型を抽象化して統一的に扱うための強力なメカニズムを提供します。これにより、ポリモーフィズム(多態性)が実現され、柔軟で拡張性の高いコードを書くことができます。
    • 例えば、io.ReaderインターフェースはReadメソッドを持つ型を定義し、ファイル、ネットワーク接続、メモリ上のバッファなど、様々なデータソースを統一的に読み込むことができます。
  • Goの既存のエンコーディングパッケージ:

    • Goの標準ライブラリには、様々なエンコーディング形式を扱うパッケージが用意されています。
      • encoding/json: JSON形式のデータをGoの型との間で変換します。
      • encoding/gob: Go独自のバイナリエンコーディング形式であるGob形式のデータをGoの型との間で変換します。
      • encoding/xml: XML形式のデータをGoの型との間で変換します。
      • encoding/base64: バイナリデータをBase64文字列に変換します。
      • encoding/hex: バイナリデータを16進数文字列に変換します。
    • これらのパッケージは、それぞれ独自のMarshal(エンコード)およびUnmarshal(デコード)関数を提供し、Goの型と特定のエンコーディング形式の間でデータを変換します。

技術的詳細

このコミットで導入されるencodingパッケージは、以下の4つのインターフェースを定義します。これらは、Goの型が自身をバイナリまたはテキスト形式にエンコード/デコードする方法を標準化するためのものです。

  1. BinaryMarshaler インターフェース:

    type BinaryMarshaler interface {
        MarshalBinary() (data []byte, err error)
    }
    
    • このインターフェースは、オブジェクトが自身をバイナリ形式にマーシャリング(エンコード)できることを示します。
    • MarshalBinaryメソッドは、レシーバ(インターフェースを実装するオブジェクト自身)をバイナリ形式にエンコードし、結果のバイトスライスとエラーを返します。
    • encoding/gobのようなバイナリエンコーディングパッケージは、このインターフェースを実装する型を見つけると、その型のMarshalBinaryメソッドを呼び出してバイナリデータを取得し、エンコード処理を行います。
  2. BinaryUnmarshaler インターフェース:

    type BinaryUnmarshaler interface {
        UnmarshalBinary(data []byte) error
    }
    
    • このインターフェースは、オブジェクトがバイナリ表現から自身をアンマーシャリング(デコード)できることを示します。
    • UnmarshalBinaryメソッドは、MarshalBinaryによって生成された形式のデータをデコードできる必要があります。
    • デコードされたデータを保持したい場合、UnmarshalBinaryは引数として渡されたdataスライスをコピーする必要があります。これは、dataスライスがメソッドの呼び出し元によって再利用される可能性があるためです。
    • encoding/gobのようなバイナリエンコーディングパッケージは、このインターフェースを実装する型にバイナリデータをデコードする際に、その型のUnmarshalBinaryメソッドを呼び出します。
  3. TextMarshaler インターフェース:

    type TextMarshaler interface {
        MarshalText() (text []byte, err error)
    }
    
    • このインターフェースは、オブジェクトが自身をテキスト形式にマーシャリング(エンコード)できることを示します。
    • MarshalTextメソッドは、レシーバをUTF-8エンコードされたテキスト形式にエンコードし、結果のバイトスライスとエラーを返します。
    • encoding/jsonencoding/xmlのようなテキストベースのエンコーディングパッケージは、このインターフェースを実装する型を見つけると、その型のMarshalTextメソッドを呼び出してテキストデータを取得し、エンコード処理を行います。
  4. TextUnmarshaler インターフェース:

    type TextUnmarshaler interface {
        UnmarshalText(text []byte) error
    }
    
    • このインターフェースは、オブジェクトがテキスト表現から自身をアンマーシャリング(デコード)できることを示します。
    • UnmarshalTextメソッドは、MarshalTextによって生成された形式のテキストをデコードできる必要があります。
    • デコードされたテキストを保持したい場合、UnmarshalTextは引数として渡されたtextスライスをコピーする必要があります。
    • encoding/jsonencoding/xmlのようなテキストベースのエンコーディングパッケージは、このインターフェースを実装する型にテキストデータをデコードする際に、その型のUnmarshalTextメソッドを呼び出します。

これらのインターフェースの導入により、Goの型は一度これらのインターフェースを実装すれば、複数のエンコーディングパッケージで統一的に扱われるようになります。例えば、time.Time型がTextMarshalerTextUnmarshalerを実装することで、JSONやXMLに変換する際に、その型が定義したカスタムのテキスト表現が使用されるようになります。これは、Go 1.2でtime.Time型がこれらのインターフェースを実装したことからも明らかです。

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

このコミットによる主なコード変更は以下の3つのファイルにわたります。

  1. src/cmd/dist/build.c:

    • Goのビルドシステムの一部であるdistツールが使用するC言語のソースファイルです。
    • install関数内で、コンパイル時の定義(-Dフラグ)にGOOS_GOARCH_%s_%sという新しい形式が追加されました。これは、特定のOSとアーキテクチャの組み合わせに応じた条件付きコンパイルを可能にするためのものです。
    • buildorder配列(ビルド順序を定義)とcleantab配列(クリーンアップ対象を定義)に、新しく追加されるpkg/encodingが組み込まれました。これにより、encodingパッケージが他の依存パッケージよりも前にビルドされ、クリーンアップの対象となることが保証されます。
  2. src/pkg/encoding/encoding.go:

    • このコミットで新規作成されたファイルです。
    • encodingパッケージの定義と、前述のBinaryMarshaler, BinaryUnmarshaler, TextMarshaler, TextUnmarshalerの4つのインターフェースが定義されています。
    • ファイルヘッダーには、Goの標準ライブラリの慣例に従い、著作権表示とBSDスタイルのライセンス情報が含まれています。
  3. src/pkg/go/build/deps_test.go:

    • Goのビルドシステムにおけるパッケージ間の依存関係をテストするためのファイルです。
    • pkgDepsマップが更新され、encoding/gobencoding/jsonが新しいencodingパッケージに依存するようになりました。
      • "encoding/gob": {"L4", "OS"} から "encoding/gob": {"L4", "OS", "encoding"} へ変更。
      • "encoding/json": {"L4"} から "encoding/json": {"L4", "encoding"} へ変更。
    • また、encodingパッケージ自体がL4(Goの標準ライブラリの基本的な依存関係を示す内部的なカテゴリ)に依存することが追加されました。

コアとなるコードの解説

src/cmd/dist/build.c の変更

  • GOOS_GOARCH_%s_%s の追加:
    • src/cmd/dist/build.cは、GoのソースコードからGoのツールチェインや標準ライブラリをビルドする際の挙動を制御するC言語のプログラムです。
    • install関数内で、コンパイル時に-DGOOS_GOARCH_OS_ARCHのようなマクロが定義されるようになりました。これは、特定のオペレーティングシステム(GOOS)とアーキテクチャ(GOARCH)の組み合わせに特化したコードパスを有効にするために使用されます。例えば、GOOS_GOARCH_linux_amd64が定義されることで、Linux AMD64環境でのみ有効なコードを記述できるようになります。これは、Goのクロスコンパイル能力をサポートし、プラットフォーム固有の最適化や挙動を制御するために重要です。
  • pkg/encoding のビルド順序への追加:
    • buildorder配列は、Goの標準ライブラリパッケージがビルドされる順序を定義します。pkg/encodingがこの配列に追加されたことで、encodingパッケージがencoding/jsonencoding/gobなどの他のエンコーディングパッケージよりも前にビルドされることが保証されます。これは、後続のパッケージがencodingパッケージで定義されたインターフェースに依存するため、依存関係を正しく解決するために不可欠です。
    • cleantab配列は、go cleanコマンド実行時に削除されるべきビルド成果物を定義します。pkg/encodingがここに追加されたことで、ビルドされたencodingパッケージの成果物もクリーンアップの対象となります。

src/pkg/encoding/encoding.go の新規作成とインターフェース定義

  • このファイルは、Goの標準ライブラリに新しいencodingパッケージを導入します。
  • パッケージのコメントには、「encodingパッケージは、データをバイトレベルおよびテキスト表現に変換する他のパッケージと共有されるインターフェースを定義します。」と明記されており、その目的が明確に示されています。
  • 定義されている4つのインターフェース(BinaryMarshaler, BinaryUnmarshaler, TextMarshaler, TextUnmarshaler)は、Goの型が自身を特定の形式にエンコード/デコードするための標準的な契約を提供します。
    • これらのインターフェースは、MarshalBinary(), UnmarshalBinary(), MarshalText(), UnmarshalText()というメソッドシグネチャを定義しています。
    • これらのメソッドは、それぞれバイナリデータ([]byte)またはUTF-8エンコードされたテキストデータ([]byte)を生成または消費し、エラーを返すことで、エンコーディング/デコーディングの成功または失敗を通知します。
    • 特にUnmarshalBinaryUnmarshalTextのコメントにある「UnmarshalBinary must copy the data if it wishes to retain the data after returning.」という注意書きは重要です。これは、入力として渡されるバイトスライスが一時的なものである可能性があり、デコードされたデータを永続的に保持したい場合は、そのデータを内部でコピーする必要があることを示しています。これにより、呼び出し元が入力スライスを再利用しても、デコードされたオブジェクトの状態が破壊されないことが保証されます。

src/pkg/go/build/deps_test.go の変更

  • このテストファイルは、Goのパッケージ間の依存関係が正しく設定されていることを検証します。
  • encoding/gobencoding/jsonの依存関係リストに"encoding"が追加されたことは、これらのパッケージが実際に新しいencodingパッケージで定義されたインターフェースを利用するようになったことを示しています。これは、設計意図がコードに反映されていることの証拠です。
  • この変更により、ビルドシステムはencodingパッケージがencoding/gobencoding/jsonよりも先にビルドされることを確認し、依存関係の解決が正しく行われるようになります。

これらの変更は、Goの標準ライブラリにおけるエンコーディングの仕組みをより堅牢で、拡張性があり、一貫性のあるものにするための重要な一歩です。

関連リンク

参考にした情報源リンク

  • [1] google.com (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQH9CAlb5uGEUli5bL2moqXIal4kIg-ytDC0-BAieA57TVMmMkQaHa3OfqcBBVyO9acWj30_byDJ07GBK792OQHP5jEE-dxr9iOtFFytDLt_dWc1NMbUPO3qJbGQlqWjgMvLovht5ibnwOuqWzflFQc=)
  • [2] appspot.com (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEN214fnzBHTxtx9MpfobZM3KWXEFRzavH5FiuoeORJj9zLP_QkS6ukkDssD-e3G4qRFqLehIFbos1pvghrG46yrJi-A6BCYllYY4u9e1ojbynLHdu22qSJcbJL-kvQ7ET95A==)
  • [3] appspot.com (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGBDs3f7s3qK1ayKVMZ5MTd8IF5MNp1L7RQ66f00aj6jdY3FZN82XvPM-lsZDnVx85jclSzXG9DaHUGUfqzAr_h0b2gkP_mmhm3MVkxrV6bXcoBl2e7EzZD1V3AnWeng3ge0tQ==)
  • [4] googlesource.com (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGwlxDq6RO_HMRE1FD3MPMMqokYetG3ZXii5O3XLg4mlps9bjSpNoYx9XiNn0B37o1tc-X2cgUOpNjS-jSjFh2ZfHCTZvrqeysq2ltZPdQ4mkyCmODrTDgp_8mNNDVAUCbim_b9t5q7U7UX_3jWaAS-b2A8arEdT8ijFw==)
  • [5] github.com (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHSA3fIZ-4T1nDraXcVkWXpEq03vPZlaQ4Bo7fYvaSBjrMz9dTZfn1aYSUm4eKcDbvQKZE4MBoMNnDtKY3dbA75OK41oiV9rgrh-wmb7kw_FiHuCoDy_2TRhBcTYbDDbiwn2UA=)