import "gob"

gobパッケージは、gobsのストリームを管理します。gobsのバイナリ値は、Encoder(送信者)とDecoder(受信者)間で交換されます。典型的な使い方としては、rpcパッケージによって提供されるようなリモートプロシージャコール(RPC)による引数と戻り値のやりとりに使われます。

gobsのストリームは、ストリーム内にデータの形式を包括しています。ストリーム内の各データ項目の前に、その項目の型情報が格納されます。この定義は、事前に定義された型のセットを使って行われます。ポインタは送信されませんが、ポインタが指し示すものは送られます。つまり値はフラットにされます。再帰的な型も処理されますが、再帰的な値(循環したデータ)には難点があり、値が変更される可能性があります。

gobsを使うには、Encoderを作成し、それに値または値を間接参照可能なアドレスから成る一連のデータ項目を渡します。Encoderは型情報を送信する前に、すでにその型情報が送信済みかをチェックします。受信側、Decoderではエンコードされたストリームから値を復元し、ローカル変数に格納します。

送信元と送信先では、値/型が必ずしも一致する必要はありません。送信元の構造体のフィールド(名前で識別される)が、受信する変数内に存在しなければ無視されます。また、受け取る変数のフィールドが、送信された型または値には無いときは受信側で無視されます。同名のフィールドが両方に存在するときは、それらの型は互換性を持たなければなりません。受信側、送信側双方で、必要なすべての間接参照と被間接参照に対しgobsとGo言語の実際の値との変換が行われます。例を挙げると、gobの型は次のように変換できます。

struct { a, b int }

これらのどのGoの型にも送受信可能です:

struct { a, b int }	// 同じ型
*struct { a, b int }	// 構造体が間接参照
struct { *a, **b int }	// フィールドが間接参照
struct { a, b int64 }	// 型が異なる値。下を参照

これらのどの型にも受信可能です:

struct { a, b int }	// 同じ型
struct { b, a int }	// 順番は関係ありません。名前でマッチングします。
struct { a, b, c int }	// 余分なフィールドcは無視
struct { b int }	// 存在しないフィールドaは無視。データは破棄される
struct { b, c int }	// 存在しないフィールドaは無視。余分なフィールドcも無視

これらの型に受信しようとするとデコードエラーが起こります:

struct { a int; b uint }	// bの符号が違う
struct { a int; b float }	// bの型が違う
struct { }			// 共通するフィールド名が無い
struct { c, d int }		// 共通するフィールド名が無い

送信される整数は2種類あり、任意の精度を持つ符号付き整数、または任意の精度を持つ符号なし整数です。固定精度のint8、int16などはありません。goフォーマット上の区別は、単に符号のありなしだけです。下で説明するように、送信側は可変長にエンコードされた値を送信します。受信側は値を受け取り、それを変数に格納します。浮動小数点の値は常に、IEEE-754 64ビット精度(下記参照)で送られます。

符号あり整数は、どの符号あり整数の変数(int、int16、など)にも受信できます。符号なし整数も、どの符号なし整数の変数にも受信できます。そして浮動小数点値は、どの浮動小数点変数にでも受信できます。ただし、受信側の変数は受け取った値を表現することができなければなりません。できなければデコード操作は失敗します。

構造体、配列、スライスもサポートしています。文字列とバイト配列に関しては特別効率的に扱われます。(下記参照)

インタフェース、関数、チャネルはgobで送信できません。これらを含む値をエンコードしようとすると失敗します。

これ以降は、大部分のユーザーにとっては重要ではない符号化の細部について説明します。詳細はボトムアップ形式で記述します。

符号なし整数は、次の2つの方法のどちらかで送信されます。それが128未満であれば、その値による1バイトとして送信します。それ以外は、1バイトのバイト長(マイナス値)につづく最小の長さのビッグエンディアン(高バイトが先)のバイトストリームで値を送信します。このようにして、0は(00)として送信し、7は(07)、256は(FE 01 00)として送信します。

論理値は、符号なし整数としてエンコードされます。(0はfalse、1はtrue)

符号付き整数iは、符号なし整数uの範囲内でエンコードされます。まず、値を1ビット、uの範囲内で上位へシフトします。ビット0には、受信したときに補数を取る必要があるかを指定します。このエンコードアルゴリズムは、次のように表せます。:

uint u;
if i < 0 {
	u = (^i << 1) | 1	// 補数 i, bit 0 は 1
} else {
	u = (i << 1)	// 補数を取らない i, bit 0 は 0
}
encodeUnsigned(u)

これらから最下位ビットは、符号ビットと同じように見えますが、この補数ビットは一番大きい負の整数が特殊ケースではないことを保証します。例:-129=^128=(^256>>1) これのエンコードは (FE 01 01)。

浮動小数点の値は、常にfloat64値の表現として送られます。まず、値はmath.Float64bitsを使ってuint64に変換されます。uint64はその後、バイトを逆転し通常の符号なし整数と同じように送信します。バイトを逆転する理由は、指数および仮数の精度の高位から先に送信されるようにするためです。例:17.0はたった3バイトにエンコードされます。(FE 31 40)

文字列とバイトスライスは、符号なしの個数に続いて、値を複数のバイト値としてそのまま送信します。

その他のスライスと配列は、符号なしの個数に続いて、要素を、その型のgobの標準エンコードで繰り返し送信します。

構造体は、一連の組(フィールド番号、フィールド値)として送信します。フィールドの値は、その型の標準gobエンコーディングを再帰的に行い送信します。フィールドがその型のゼロ値であるときは、そのフィールドの送信は省かれます。フィールド番号は、エンコードされた構造体の型によって決まり、最初のフィールドはフィールド0、2番目はフィールド1となります。フィールド番号の値をエンコードするときは、効率を良くするため差分エンコードされます。フィールドは常にフィールド番号順に送信されるため、差分は符号なしとして扱われます。差分エンコーディングの際、フィールド番号の初期値は-1であるため、符号なし整数フィールド0の値が7であるときは、符号なし差分 = 1、符号なし整数値 = 7 (01 07)として送信されます。すべてのフィールドを送信したあと最後に、構造体の終了を表す終了マークが送信されます。このマークは、差分=0 (00)として表されます。

インタフェース型には、互換性チェックが行われません。通信において、すべてのインタフェース型は、intや[]byteと同様に、ある一つの「インタフェース」型の仲間としてみなされます。事実上これらは、interface{}とみなされます。インタフェースの値は、まず送信される実際の型を識別する文字列(名前はRegisterを呼び出して事前に定義しなければなりません)として送信され、続いて、以降のデータ長がバイト数として送られます。(データがないときは省略可)  続いて、インタフェース値に格納されている実際(動的)の値を通常通りエンコードしたものが送信されます。(nilインタフェース値は、空文字列により識別します。値は送信されません) 受信側では、decoderは、デコードした実際のアイテムが、格納先の変数のインタフェースを満たしているかを確認します。

型の表現について説明します。EncoderおよびDecoder間の接続上で型を定義するときは、符号あり整数の型idを割り当てます。Encoder.Encode(v)が呼び出されたときは、vおよびそのすべての要素の型のidが割り当てられていることを確認した上で、データの組(typeid, encoded-v)を送信します。このtypeidはvの型のidで、encoded-vはvの値をgobエンコードしたものです。

型を定義するために、Encoderは未使用の型id(正の値)を選び、データの組(-type id, encoded-type)を送信します。このencoded-typeは、下に示す構造をもつwireTypeをgobでエンコードしたものです。

type wireType struct {
	s structType
}
type arrayType struct {
	commonType
	Elem typeId
	Len  int
}
type commonType {
	name string // 構造体型の名前。
	_id  int    // 型のid。これは型の内側にあるので重複している
}
type sliceType struct {
	commonType
	Elem typeId
}
type structType struct {
	commonType
	field []*fieldType // 構造体のフィールド。
}
type fieldType struct {
	name string // フィールドの名前。
	id   int    // フィールドの型のid。前もって定義されている必要あり
}
type mapType struct {
	commonType
	Key  typeId
	Elem typeId
}

ネストした型idがあるとき、内部のすべての型idは、トップレベルの型idがencoded-vとして使用されるより前に定義されなければなりません。

セットアップを単純化するため、基本的なgobの型int、uintなどと同様に、下に示す型を接続上で扱えるよう定義済みとみなします。

bool        1
int         2
uint        3
float       4
[]byte      5
string      6
complex     7
interface   8
// 空きは予約済みid
wireType    16
arrayType   17
commonType  18
sliceType   19
structType  20
fieldType   21
// 22は、fieldTypeのスライス
mapType     23

これらをまとめると、gobのストリームは次のようになります。

((-型id, wireTypeのエンコーディング)* (型id, valueのエンコーディング))*

*は、0回以上繰り返すことを表します。型idは、事前定義されているか、ストリーム内にその値が現れる前に定義されている必要があります。

パッケージファイル

debug.go decode.go decoder.go doc.go encode.go encoder.go error.go type.go

Debug関数

func Debug(r io.Reader)

Debugは、rから読み込んだgobデータを人が読める形式で出力します。

Register関数

func Register(value interface{})

Registerは、値から型を識別できるようにするために、値内の型名を利用して型を登録します。この名前を使って、送受信されるインタフェース型変数の値の実際の型が識別されます。登録する必要があるのは、インタフェース型の値として転送しようとする型だけです。この関数は、初期化時にのみ使用されることを想定しています。型と名前のマッピングが、送信側、受信側ともに登録されていないときはパニックが発生します。

RegisterName関数

func RegisterName(name string, value interface{})

RegisterNameは、Registerと同じですが、型が持つデフォルトの名前の代わりに指定した名前を使用します。

Decoder型

Decoderは、接続のリモート側から読み込みを行い、型とデータ情報の受信を管理します。

type Decoder struct {
    // contains unexported fields
}

NewDecoder関数

func NewDecoder(r io.Reader) *Decoder

NewDecoderは、io.Readerから読み込みを行う、新しいデコーダを返します。

(*Decoder) Decode関数

func (dec *Decoder) Decode(e interface{}) os.Error

Decodeは、接続から次の値を読み込み、それを空インタフェースの値のデータ表現として格納します。eの実際の型は、受信しようとしているデータ項目を格納するのに適した型でなければならず、またポインタでなければなりません。

(*Decoder) DecodeValue関数

func (dec *Decoder) DecodeValue(value reflect.Value) os.Error

DecodeValueは、接続から次の値を読み込み、それをvalue(リフレクション)のデータ表現として格納します。valueは、受信しようとしているデータ項目を格納するのに適した型でなければなりません。

Encoder型

Encoderは、接続のもう一方への型とデータ情報の送信を管理します。

type Encoder struct {
    // contains unexported fields
}

NewEncoder関数

func NewEncoder(w io.Writer) *Encoder

NewEncoderは、io.Writerへ送信を行う、新しいエンコーダを返します。

(*Encoder) Encode関数

func (enc *Encoder) Encode(e interface{}) os.Error

Encodeは、空インタフェースの値で表現しているデータ項目を送信します。このとき、必要な型情報が先に送信されることは保証されます。

(*Encoder) EncodeValue関数

func (enc *Encoder) EncodeValue(value reflect.Value) os.Error

EncodeValueは、value(リフレクション)が表現しているデータ項目を送信します。このとき、必要な型情報が先に送信されることは保証されます。