...

パッケージ gob

import "encoding/gob"
概要
目次

概要 ▾

gob パッケージは,エンコーダ (送信器) とデコーダ (受信器) 間で交換されるバイナリ値である gob のストリームを管理します。 典型的な使用例は,"net/rpc" パッケージで提供されるようなリモートプロシージャコール (RPC) の引数と結果を渡すときに使います。

この実装は,ストリーム内の各データ型のカスタムコーデックをコンパイルします。 1 つのエンコーダを使用して値のストリームを送信し,コンパイルのコストを削減する場合に最も効率的です。

基本

gob の流れは自己記述的です。 ストリーム内の各データ項目の前には,その型の指定があります。 これは,事前定義済みの型の小さなセットで表されます。 ポインタは送信されませんが,それらが指すものは送信されます。 つまり,値が平坦化されます。 値がないため, Nil ポインタは許可されていません。 再帰型は問題なく動作しますが,再帰的な値 (周期を含むデータ) は問題があります。 これは変わるかもしれません。

gob を使用するには,エンコーダを作成し,それに一連のデータ項目を値またはアドレスとして参照できるアドレスとして表示します。 エンコーダは,すべての型情報が必要になる前に送信されるようにします。 受信側では, Decoder がエンコードされたストリームから値を取得し,それらをローカル変数に展開します。

型と値

転送元と転送先の値 / 型は正確に一致する必要はありません。 構造体の場合,ソース内にあるが受け取り変数にないフィールド (名前によって識別される) は無視されます。 受信変数にはあるが送信型または値に欠落しているフィールドは,宛先では無視されます。 同じ名前のフィールドが両方に存在する場合,それらの型は互換性がなければなりません。 レシーバとトランスミッタの両方が,gob と実際の 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 つの方法で転送されます。 任意精度の符号付き整数または任意精度の符号なし整数。 gob フォーマットには int8, int16 などの区別はありません。 符号付き整数と符号なし整数のみがあります。 後述するように,送信機は可変長符号化で値を送信します。 受信側はその値を受け取り,それを変換先変数に格納します。 浮動小数点数は,常に IEEE-754 64 ビット精度を使用して送信されます (下記参照) 。

符号付き整数は,任意の符号付き整数変数 (int, int16 など) で受け取ることができます。 符号なし整数は,任意の符号なし整数変数で受け取ることができます。 浮動小数点値は,任意の浮動小数点変数で受け取ることができます。 ただし,変換先変数は値を表すことができなければならず,そうでなければデコード操作は失敗します。

構造体,配列,スライスもサポートされています。 構造体はエクスポートされたフィールドのみをエンコードおよびデコードします。 文字列とバイト配列は,特別で効率的な表現でサポートされています (下記参照) 。 スライスがデコードされるとき,既存のスライスが容量を持っていれば,スライスはその場で拡張されます。 そうでなければ,新しい配列が割り当てられます。 結果のスライスの長さはデコードされた要素の数を報告します。

一般に,割り当てが必要な場合,デコーダはメモリを割り当てます。 そうでない場合は,ストリームから読み取った値で変換先変数を更新します。 それらが最初に初期化されないので,変換先が map, struct ,または slice などの複合値である場合,デコードされた値は要素ごとに既存の変数にマージされます。

関数とチャンネルは gob で送信されません。 最上位レベルでそのような値をエンコードしようとしても失敗します。 chan または func 型の構造体フィールドは,エクスポートされていないフィールドとまったく同じように扱われ,無視されます。

Gob は, GobEncoder または encoding.BinaryMarshaler インターフェースを実装している任意の型の値を,対応するメソッドをその優先順に呼び出してエンコードできます。

Gob は, GobDecoder または encoding.BinaryUnmarshaler インターフェースを実装している任意の型の値を,この優先順で対応するメソッドを呼び出すことによってデコードできます。

エンコーディングの詳細

このセクションでは,エンコーディング,ほとんどのユーザーにとって重要ではない詳細について説明します。 詳細はボトムアップで表示されます。

符号なし整数は, 2 つの方法のうちの 1 つで送信されます。 128 未満の場合は,その値を持つバイトとして送信されます。 それ以外の場合は,値を保持する最小長のビッグエンディアン (上位バイト先頭) バイトストリームとして送信され,その後にバイトカウントを保持する 1 バイトが否定されます。 したがって,0は (00) として送信され,7は (07) として送信され,256は (FE 01 00) として送信される。

ブール値は,符号なし整数 (0 の場合は偽, 1 の場合は真) で符号化されます。

符号付き整数 i は,符号なし整数 u の中に符号化されています。 u の中では,ビット 1 は上方向に値を含みます。 ビット 0 は,受信時に補完する必要があるかどうかを示します。 エンコードアルゴリズムは次のようになります。

var u uint
if i < 0 {
	u = (^uint(i) << 1) | 1 // complement i, bit 0 is 1
} else {
	u = (uint(i) << 1) // do not complement i, bit 0 is 0
}
encodeUnsigned(u)

したがって,下位ビットは符号ビットに似ていますが,それを補数ビットにすることで,最大の負の整数が特別な場合ではないことが保証されます。 例えば, -129=^128=(^256>>1) は (FE 01 01) としてエンコードします。

浮動小数点数は常に float64 値の表現として送信されます。 その値は math.Float64bits を使って uint64 に変換されます。 uint64 はバイト反転され,通常の符号なし整数として送信されます。 バイト反転とは,仮数部の指数部と高精度部分が最初になることを意味します。 下位ビットはしばしばゼロであるので,これは符号化バイトを節約することができます。 たとえば, 17.0 は 3 バイトのみでエンコードされています (FE 31 40) 。

バイトの文字列とスライスは,符号なしのカウントとして送信され,その後に多くの未解釈の値のバイトが続きます。

他のすべてのスライスと配列は,符号なしのカウントとして送信され,その後にその型に標準の gob エンコーディングを使用している多くの要素が再帰的に送信されます。

マップは符号なしのカウントとして送信され,その後に多数のキーと要素のペアが続きます。 空だが nil 以外のマップが送信されるので,受信側がまだ割り当てていない場合は,送信されたマップが nil でトップレベルでない限り,常に受信時に割り当てられる。

スライスや配列,さらにはマップでは,すべての要素がゼロであっても,ゼロ値の要素であってもすべての要素が転送されます。

構造体は一連の (フィールド番号,フィールド値) ペアとして送信されます。 フィールド値は,その型の標準gob 符号化を使用して再帰的に送信されます。 フィールドの型がゼロ値の場合 (配列を除く。 上記を参照) ,送信から省略されます。 フィールド番号は,エンコードされた構造体の型によって定義されます。 エンコードされた型の最初のフィールドはフィールド 0 , 2 番目のフィールドはフィールド 1 などです。 値をエンコードする場合,効率のためにフィールド番号はデルタエンコードされます。 フィールド番号の昇順に送信されます。 したがって,デルタは符号なしです。 デルタエンコーディングの初期化はフィールド番号を -1 に設定するので,値 7 の符号なし整数フィールド 0 が符号なしデルタ = 1 ,符号なし値 = 7 ,または (01 07) として送信されます。 最後に,すべてのフィールドが送信された後,終了マークは構造体の終わりを示します。 そのマークは delta=0 の値で,表現は (00) です。

インターフェース型は互換性についてチェックされません。 すべてのインターフェース型は,伝送のために, int または []byte に類似した 1 つの " インターフェース " 型のメンバーとして扱われます - 実際,それらはすべて interface{} として扱われます。 インターフェース値は,送信される具象型を識別するストリング (Register を呼び出すことによって事前定義されている必要がある名前) として送信され,その後に続くデータの長さのバイトカウントが続きます。 interface 値に格納された具象 (動的) 値の通常のエンコードが続きます。 受信時に,デコーダは,展開された具象アイテムが受信変数のインターフェースを満たすことを確認します。

値が Encode に渡され,型が構造体 (または構造体へのポインタなど) ではない場合,処理を簡単にするために 1 つのフィールドの構造体として表されます。 これの唯一の目に見える影響は,エンコードされた構造体の最後のフィールドの後のように,値の後にゼロバイトをエンコードすることで,デコードアルゴリズムはトップレベルの値がいつ完了するかを認識します。

型の表現については後述します。 型がエンコーダとデコーダの間の特定の接続で定義されている場合は,符号付き整数型の ID が割り当てられます。 Encoder.Encode(v) が呼び出されると, v の型とそのすべての要素に割り当てられた ID があることを確認してから,ペア (typeid, encoded-v) を送信します。 ここで, typeid は符号化型の型 ID です。 of v および encoded-v は,値 v のgob 符号化です。

型を定義するために,エンコーダは未使用の正の型 ID を選択し,ペア (-type id, encoded-type) を送信します。 encoded-type は,これらの型から構成された wireType 記述の gob エンコーディングです。

type wireType struct {
	ArrayT           *ArrayType
	SliceT           *SliceType
	StructT          *StructType
	MapT             *MapType
	GobEncoderT      *gobEncoderType
	BinaryMarshalerT *gobEncoderType
	TextMarshalerT   *gobEncoderType

}
type arrayType struct {
	CommonType
	Elem typeId
	Len  int
}
type CommonType struct {
	Name string // 構造体型の名前
	Id  int    // 型のID, repeated so it's inside the type
}
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
}
type gobEncoderType struct {
	CommonType
}

入れ子になった型 ID がある場合は,最上位の型 ID を使用して encoded-v を記述する前に,すべての内部型 ID の型を定義する必要があります。

セットアップを簡単にするために,接続はこれらの型を先験的に理解するように定義されています。 また,基本的な 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

最後に, Encode の呼び出しによって作成された各メッセージの前には,メッセージ内に残っているバイト数の符号化された符号なし整数カウントが続きます。 初期型名の後,インターフェース値は同じ方法でラップされます。 実際には,インターフェース値は Encode の再帰呼び出しのように機能します。

まとめると,gob ストリームは次のようになります。

(バイト数 (-型 ID, wireType のエンコード)* (型 ID, 値のエンコード))*

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

互換性 : パッケージに対する将来の変更は,以前のバージョンを使用してエンコードされたストリームとの互換性を維持するように努めます。 つまり,このパッケージのどのリリース版でも,セキュリティ修正などの問題を条件として,以前のリリース版で書き込まれたデータをデコードできるはずです。 背景については Go 互換性文書を参照してください : https://golang.org/doc/go1compat

gob ワイヤーフォーマットのデザインディスカッションについては, "Gobs of data" を参照してください。 https://blog.golang.org/gobs-of-data

例 (Basic)

この例は,パッケージの基本的な使い方を示しています。 エンコーダを作成し,いくつかの値を送信し,それらをデコーダで受信します。

コード:

package gob_test

import (
    "bytes"
    "encoding/gob"
    "fmt"
    "log"
)

type P struct {
    X, Y, Z int
    Name    string
}

type Q struct {
    X, Y *int32
    Name string
}

// この例は,パッケージの基本的な使い方を示しています。
// エンコーダを作成し,いくつかの値を送信し,それらをデコーダで受信します。
func Example_basic() {
    // エンコーダとデコーダを初期化します。
    // 通常, enc と dec はネットワーク接続にバインドされ,エンコーダとデコーダは異なるプロセスで動作します。
    var network bytes.Buffer        // ネットワーク接続の代理
    enc := gob.NewEncoder(&network) // ネットワークに書き込みます。
    dec := gob.NewDecoder(&network) // ネットワークから読みます。

    // いくつかの値をエンコード (送信) します。
    err := enc.Encode(P{3, 4, 5, "Pythagoras"})
    if err != nil {
        log.Fatal("encode error:", err)
    }
    err = enc.Encode(P{1782, 1841, 1922, "Treehouse"})
    if err != nil {
        log.Fatal("encode error:", err)
    }

    // 値をデコード (受信) して表示します。
    var q Q
    err = dec.Decode(&q)
    if err != nil {
        log.Fatal("decode error 1:", err)
    }
    fmt.Printf("%q: {%d, %d}\n", q.Name, *q.X, *q.Y)
    err = dec.Decode(&q)
    if err != nil {
        log.Fatal("decode error 2:", err)
    }
    fmt.Printf("%q: {%d, %d}\n", q.Name, *q.X, *q.Y)

    // Output:
    // "Pythagoras": {3, 4}
    // "Treehouse": {1782, 1841}
}

例 (EncodeDecode)

この例では,カスタムのエンコード方法とデコード方法を実装する値を送信します。

コード:

package gob_test

import (
    "bytes"
    "encoding/gob"
    "fmt"
    "log"
)

// Vector 型にはエクスポートされていないフィールドがあり,パッケージからアクセスすることはできません。
// そのため, gob パッケージで型を送受信できるようにするために BinaryMarshal/BinaryUnmarshal メソッドのペアを作成します。
// これらのインターフェースは "encoding" パッケージで定義されています。
// ローカルに定義された GobEncode/GobDecoder インターフェースも同等に使用できます。
type Vector struct {
    x, y, z int
}

func (v Vector) MarshalBinary() ([]byte, error) {
    // 単純なエンコーディング: プレーンテキスト
    var b bytes.Buffer
    fmt.Fprintln(&b, v.x, v.y, v.z)
    return b.Bytes(), nil
}

// UnmarshalBinary はレシーバを変更するので,ポインタレシーバを使用する必要があります。
func (v *Vector) UnmarshalBinary(data []byte) error {
    // 単純なエンコーディング: プレーンテキスト
    b := bytes.NewBuffer(data)
    _, err := fmt.Fscanln(b, &v.x, &v.y, &v.z)
    return err
}

// この例では,カスタムのエンコード方法とデコード方法を実装する値を送信します。
func Example_encodeDecode() {
    var network bytes.Buffer // ネットワークの代役です。

    // エンコーダを作成して値を送信します。
    enc := gob.NewEncoder(&network)
    err := enc.Encode(Vector{3, 4, 5})
    if err != nil {
        log.Fatal("encode:", err)
    }

    // デコーダを作成して値を受け取ります。
    dec := gob.NewDecoder(&network)
    var v Vector
    err = dec.Decode(&v)
    if err != nil {
        log.Fatal("decode:", err)
    }
    fmt.Println(v)

    // Output:
    // {3 4 5}
}

例 (Interface)

この例は,インターフェース値をエンコードする方法を示しています。 通常の型との主な違いは,インターフェースを実装する具象型を登録することです。

コード:

package gob_test

import (
    "bytes"
    "encoding/gob"
    "fmt"
    "log"
    "math"
)

type Point struct {
    X, Y int
}

func (p Point) Hypotenuse() float64 {
    return math.Hypot(float64(p.X), float64(p.Y))
}

type Pythagoras interface {
    Hypotenuse() float64
}

// この例は,インターフェース値をエンコードする方法を示しています。
// 通常の型との主な違いは,インターフェースを実装する具象型を登録することです。
func Example_interface() {
    var network bytes.Buffer // ネットワークの代役です。

    // エンコーダとデコーダ (通常はエンコーダとは別のマシンにあります) の具体的な型を登録する必要があります。
    // それぞれの側で,エンジンに,インターフェースを実装するどの具象型が送信されているのかを伝えます。
    gob.Register(Point{})

    // エンコーダを作成していくつかの値を送信します。
    enc := gob.NewEncoder(&network)
    for i := 1; i <= 3; i++ {
        interfaceEncode(enc, Point{3 * i, 4 * i})
    }

    // デコーダを作成していくつかの値を受け取ります。
    dec := gob.NewDecoder(&network)
    for i := 1; i <= 3; i++ {
        result := interfaceDecode(dec)
        fmt.Println(result.Hypotenuse())
    }

    // Output:
    // 5
    // 10
    // 15
}

// interfaceEncode は,インターフェース値をエンコーダに渡してエンコードします。
func interfaceEncode(enc *gob.Encoder, p Pythagoras) {
    // 具象型が登録されていない限り,エンコードは失敗します。
    // 呼び出し元の関数で登録しています。

    // Encode がインターフェース型の値を認識するように (そして送信するように) インターフェースにポインタを渡します。
    // p を直接渡すと,代わりに具象型と見られます。
    // 背景については,ブログ投稿 "The Laws of Reflection" を参照してください。
    err := enc.Encode(&p)
    if err != nil {
        log.Fatal("encode:", err)
    }
}

// interfaceDecode は,ストリームから次のインターフェース値をデコードして返します。
func interfaceDecode(dec *gob.Decoder) Pythagoras {
    // ワイヤ上の具象型が登録されていない限り,デコードは失敗します。
    // 呼び出し元の関数で登録しています。
    var p Pythagoras
    err := dec.Decode(&p)
    if err != nil {
        log.Fatal("decode:", err)
    }
    return p
}

func Register

func Register(value interface{})

Register は,その内部型名の下に,その型の値で識別される型を記録します。 その名前は,インターフェース変数として送受信される値の具体的な型を識別します。 登録する必要があるのは,インターフェース値の実装として転送される型だけです。 初期化中にのみ使用されることを期待して,それは型と名前の間のマッピングが全単射ではないならパニックします。

func RegisterName

func RegisterName(name string, value interface{})

RegisterName は Register に似ていますが,型のデフォルトではなく name を使用します。

type CommonType

CommonType はすべての型の要素を保持します。 これはバイナリ互換性のために残されており,パッケージの型記述子のエンコーディングのためだけにエクスポートされています。 クライアントによる直接使用は意図されていません。

type CommonType struct {
    Name string
    Id   typeId
}

type Decoder

Decoder (デコーダ) は,接続のリモート側から読み取られた型とデータ情報の受信を管理します。 複数のゴルーチンから安全に平行使用できます。

Decoder はデコードされた入力サイズに対して基本的な健全性チェックのみを行います。 リミットを設定することはできません。 信頼できないソースから gob データをデコードするときは注意してください。

type Decoder struct {
    // エクスポートされていないフィールドがあります
}

func NewDecoder

func NewDecoder(r io.Reader) *Decoder

NewDecoder は, io.Reader から読み取る新しいデコーダを返します。 r が io.ByteReader を実装していない場合は, bufio.Reader にラップされます。

func (*Decoder) Decode

func (dec *Decoder) Decode(e interface{}) error

Decode (デコード) は,入力ストリームから次の値を読み取り,それを空のインターフェース値で表されるデータに保管します。 e が nil の場合,値は破棄されます。 そうでなければ, e の内部の値は,受信した次のデータ項目の正しい型へのポインターでなければなりません。 入力が EOF の場合, Decode は io.EOF を返し, e を変更しません。

func (*Decoder) DecodeValue

func (dec *Decoder) DecodeValue(v reflect.Value) error

DecodeValue は入力ストリームから次の値を読み込みます。 v が ゼロ reflect.Value (v.Kind() == Invalid) の場合, DecodeValue は値を破棄します。 それ以外の場合は,値を v に格納します。 その場合, v はデータへの非 nil ポインターを表すか,割り当て可能な reflect.Value (v.CanSet()) でなければなりません。 入力が EOF の場合, DecodeValue は io.EOF を返します。 v を変更しません。

type Encoder

Encoder は,接続の反対側への型とデータ情報の送信を管理します。 複数のゴルーチンによる平行使用は安全です。

type Encoder struct {
    // エクスポートされていないフィールドがあります
}

func NewEncoder

func NewEncoder(w io.Writer) *Encoder

NewEncoder は, io.Writer で送信する新しいエンコーダを返します。

func (*Encoder) Encode

func (enc *Encoder) Encode(e interface{}) error

Encode は空のインターフェース値で表されるデータ項目を送信し,必要なすべての型情報が最初に送信されたことを保証します。 エンコーダに nil ポインタを渡すと,それらが gob によって送信され得ないのでパニックします。

func (*Encoder) EncodeValue

func (enc *Encoder) EncodeValue(value reflect.Value) error

EncodeValue はリフレクション値で表されるデータ項目を送信し,必要なすべての型情報が最初に送信されたことを保証します。 EncodeValue に nil ポインタを渡すと,それらが gob によって送信されることができないのでパニックします。

type GobDecoder

GobDecoder は, GobEncoder によって送信された送信値をデコードするための独自のルーチンを提供するデータを記述するインターフェースです。

type GobDecoder interface {
    // GobDecode は,通常は同じ具象型について, GobEncode によって書き込まれたバイトスライスで表される値で,ポインタでなければならない受信側を上書きします。
    GobDecode([]byte) error
}

type GobEncoder

GobEncoder は, GobDecoder に送信する値をエンコードするための独自の表現を提供するデータを記述するインターフェースです。 GobEncoder と GobDecoder を実装する型は,そのデータの表現を完全に制御するため,プライベートフィールド,チャンネル,関数など,通常 gob ストリームでは伝達できないものを含むことがあります。

注 :Gob は永続的に保存できるので, GobEncoder で使用されるエンコードがソフトウェアの進化に合わせて安定していることを保証するのは良い設計です。 例えば, GobEncode がエンコーディングにバージョン番号を含めることは意味があります。

type GobEncoder interface {
    // GobEncode は, GobDecoder に送信するための受信機のエンコードを表すバイトスライスを返します。
    // 通常は同じ具象型です。
    GobEncode() ([]byte, error)
}