[インデックス 17219] ファイルの概要
このコミットは、Go言語の標準ライブラリにencoding
パッケージを新規追加するものです。このパッケージは、バイナリ形式およびテキスト形式のデータ変換(エンコーディング/デコーディング)を行うための共通インターフェースを定義します。これにより、encoding/gob
、encoding/json
、encoding/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
で提案された設計では、TextMarshaler
やBinaryMarshaler
といった共通のインターフェースを導入することで、この問題を解決しようとしました。これらのインターフェースを型が実装することで、その型はどのエンコーディングパッケージからでも、そのインターフェースを通じて統一的にエンコード・デコードされることが期待されます。これにより、例えば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の型と特定のエンコーディング形式の間でデータを変換します。
- Goの標準ライブラリには、様々なエンコーディング形式を扱うパッケージが用意されています。
技術的詳細
このコミットで導入されるencoding
パッケージは、以下の4つのインターフェースを定義します。これらは、Goの型が自身をバイナリまたはテキスト形式にエンコード/デコードする方法を標準化するためのものです。
-
BinaryMarshaler
インターフェース:type BinaryMarshaler interface { MarshalBinary() (data []byte, err error) }
- このインターフェースは、オブジェクトが自身をバイナリ形式にマーシャリング(エンコード)できることを示します。
MarshalBinary
メソッドは、レシーバ(インターフェースを実装するオブジェクト自身)をバイナリ形式にエンコードし、結果のバイトスライスとエラーを返します。encoding/gob
のようなバイナリエンコーディングパッケージは、このインターフェースを実装する型を見つけると、その型のMarshalBinary
メソッドを呼び出してバイナリデータを取得し、エンコード処理を行います。
-
BinaryUnmarshaler
インターフェース:type BinaryUnmarshaler interface { UnmarshalBinary(data []byte) error }
- このインターフェースは、オブジェクトがバイナリ表現から自身をアンマーシャリング(デコード)できることを示します。
UnmarshalBinary
メソッドは、MarshalBinary
によって生成された形式のデータをデコードできる必要があります。- デコードされたデータを保持したい場合、
UnmarshalBinary
は引数として渡されたdata
スライスをコピーする必要があります。これは、data
スライスがメソッドの呼び出し元によって再利用される可能性があるためです。 encoding/gob
のようなバイナリエンコーディングパッケージは、このインターフェースを実装する型にバイナリデータをデコードする際に、その型のUnmarshalBinary
メソッドを呼び出します。
-
TextMarshaler
インターフェース:type TextMarshaler interface { MarshalText() (text []byte, err error) }
- このインターフェースは、オブジェクトが自身をテキスト形式にマーシャリング(エンコード)できることを示します。
MarshalText
メソッドは、レシーバをUTF-8エンコードされたテキスト形式にエンコードし、結果のバイトスライスとエラーを返します。encoding/json
やencoding/xml
のようなテキストベースのエンコーディングパッケージは、このインターフェースを実装する型を見つけると、その型のMarshalText
メソッドを呼び出してテキストデータを取得し、エンコード処理を行います。
-
TextUnmarshaler
インターフェース:type TextUnmarshaler interface { UnmarshalText(text []byte) error }
- このインターフェースは、オブジェクトがテキスト表現から自身をアンマーシャリング(デコード)できることを示します。
UnmarshalText
メソッドは、MarshalText
によって生成された形式のテキストをデコードできる必要があります。- デコードされたテキストを保持したい場合、
UnmarshalText
は引数として渡されたtext
スライスをコピーする必要があります。 encoding/json
やencoding/xml
のようなテキストベースのエンコーディングパッケージは、このインターフェースを実装する型にテキストデータをデコードする際に、その型のUnmarshalText
メソッドを呼び出します。
これらのインターフェースの導入により、Goの型は一度これらのインターフェースを実装すれば、複数のエンコーディングパッケージで統一的に扱われるようになります。例えば、time.Time
型がTextMarshaler
とTextUnmarshaler
を実装することで、JSONやXMLに変換する際に、その型が定義したカスタムのテキスト表現が使用されるようになります。これは、Go 1.2でtime.Time
型がこれらのインターフェースを実装したことからも明らかです。
コアとなるコードの変更箇所
このコミットによる主なコード変更は以下の3つのファイルにわたります。
-
src/cmd/dist/build.c
:- Goのビルドシステムの一部である
dist
ツールが使用するC言語のソースファイルです。 install
関数内で、コンパイル時の定義(-D
フラグ)にGOOS_GOARCH_%s_%s
という新しい形式が追加されました。これは、特定のOSとアーキテクチャの組み合わせに応じた条件付きコンパイルを可能にするためのものです。buildorder
配列(ビルド順序を定義)とcleantab
配列(クリーンアップ対象を定義)に、新しく追加されるpkg/encoding
が組み込まれました。これにより、encoding
パッケージが他の依存パッケージよりも前にビルドされ、クリーンアップの対象となることが保証されます。
- Goのビルドシステムの一部である
-
src/pkg/encoding/encoding.go
:- このコミットで新規作成されたファイルです。
encoding
パッケージの定義と、前述のBinaryMarshaler
,BinaryUnmarshaler
,TextMarshaler
,TextUnmarshaler
の4つのインターフェースが定義されています。- ファイルヘッダーには、Goの標準ライブラリの慣例に従い、著作権表示とBSDスタイルのライセンス情報が含まれています。
-
src/pkg/go/build/deps_test.go
:- Goのビルドシステムにおけるパッケージ間の依存関係をテストするためのファイルです。
pkgDeps
マップが更新され、encoding/gob
とencoding/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/json
やencoding/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
)を生成または消費し、エラーを返すことで、エンコーディング/デコーディングの成功または失敗を通知します。 - 特に
UnmarshalBinary
とUnmarshalText
のコメントにある「UnmarshalBinary
must copy the data if it wishes to retain the data after returning.」という注意書きは重要です。これは、入力として渡されるバイトスライスが一時的なものである可能性があり、デコードされたデータを永続的に保持したい場合は、そのデータを内部でコピーする必要があることを示しています。これにより、呼び出し元が入力スライスを再利用しても、デコードされたオブジェクトの状態が破壊されないことが保証されます。
- これらのインターフェースは、
src/pkg/go/build/deps_test.go
の変更
- このテストファイルは、Goのパッケージ間の依存関係が正しく設定されていることを検証します。
encoding/gob
とencoding/json
の依存関係リストに"encoding"
が追加されたことは、これらのパッケージが実際に新しいencoding
パッケージで定義されたインターフェースを利用するようになったことを示しています。これは、設計意図がコードに反映されていることの証拠です。- この変更により、ビルドシステムは
encoding
パッケージがencoding/gob
やencoding/json
よりも先にビルドされることを確認し、依存関係の解決が正しく行われるようになります。
これらの変更は、Goの標準ライブラリにおけるエンコーディングの仕組みをより堅牢で、拡張性があり、一貫性のあるものにするための重要な一歩です。
関連リンク
- Go 1.2 Encoding Package Design: https://golang.org/s/go12encoding
- Go CL 12541051 (Gerrit Change-Id): https://golang.org/cl/12541051
参考にした情報源リンク
- [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=)