github.com/shogo82148/std@v1.22.1-0.20240327122250-4e474527810c/encoding/gob/doc.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  /*
     6  gobパッケージは、gobのストリームを管理します - これは、
     7  [Encoder](送信者)と [Decoder](受信者)間で交換されるバイナリ値です。
     8  典型的な使用例は、リモートプロシージャコール(RPC)の引数と結果を転送することです。
     9  これは [net/rpc] によって提供されます。
    10  
    11  実装は、ストリーム内の各データ型に対してカスタムコーデックをコンパイルし、
    12  コンパイルのコストを分散させるために、単一の [Encoder] が値のストリームを送信するときに最も効率的です。
    13  
    14  # 基本
    15  
    16  gobのストリームは自己記述的です。ストリーム内の各データ項目は、
    17  その型の仕様によって先行します。これは、事前に定義された小さな型セットの観点から表現されます。
    18  ポインタは伝送されませんが、それらが指すものは伝送されます。つまり、値はフラット化されます。
    19  nilポインタは許可されていません、なぜならそれらには値がないからです。
    20  再帰的な型はうまく動作しますが、再帰的な値(サイクルを持つデータ)は問題となります。これは変わるかもしれません。
    21  
    22  gobを使用するには、[Encoder] を作成し、それに一連のデータ項目を
    23  値または値に逆参照できるアドレスとして提示します。[Encoder] は
    24  すべての型情報が必要になる前に送信されることを確認します。受信側では、
    25  [Decoder] がエンコードされたストリームから値を取得し、それらをローカル
    26  変数に展開します。
    27  
    28  # 型と値
    29  
    30  ソースと宛先の値/型は、正確に一致する必要はありません。構造体の場合、
    31  ソースに存在するが受信変数から欠落しているフィールド(名前で識別)は無視されます。
    32  受信変数に存在するが、送信された型または値から欠落しているフィールドは、
    33  宛先では無視されます。同じ名前のフィールドが両方に存在する場合、
    34  その型は互換性がなければなりません。受信者と送信者の両方が、
    35  gobと実際のGoの値との間で必要なすべての間接参照と逆参照を行います。
    36  例えば、スキーマ的には、gobの型は以下のようになります。
    37  
    38  	struct { A, B int }
    39  
    40  以下のGoの型から送信されるか、または受信することができます:
    41  
    42  	struct { A, B int }	// 同じ
    43  	*struct { A, B int }	// 構造体の追加の間接参照
    44  	struct { *A, **B int }	// フィールドの追加の間接参照
    45  	struct { A, B int64 }	// 異なる具体的な値の型; 下記参照
    46  
    47  以下のいずれかにも受信することができます:
    48  
    49  	struct { A, B int }	// 同じ
    50  	struct { B, A int }	// 順序は関係ありません; 名前でマッチングします
    51  	struct { A, B, C int }	// 追加のフィールド(C)は無視されます
    52  	struct { B int }	// 欠落しているフィールド(A)は無視されます; データは破棄されます
    53  	struct { B, C int }	// 欠落しているフィールド(A)は無視されます; 追加のフィールド(C)も無視されます。
    54  
    55  これらの型に受信しようとすると、デコードエラーが発生します:
    56  
    57  	struct { A int; B uint }	// Bの符号が変わります
    58  	struct { A int; B float }	// Bの型が変わります
    59  	struct { }			// 共通のフィールド名がありません
    60  	struct { C, D int }		// 共通のフィールド名がありません
    61  
    62  整数は2つの方法で伝送されます: 任意の精度を持つ符号付き整数または
    63  任意の精度を持つ符号なし整数。gob形式ではint8、int16などの
    64  区別はありません。符号付きと符号なしの整数のみが存在します。以下で
    65  説明するように、送信者は可変長エンコーディングで値を送信します。
    66  受信者は値を受け入れ、それを宛先変数に格納します。
    67  浮動小数点数は常にIEEE-754 64ビット精度を使用して送信されます(以下参照)。
    68  
    69  符号付き整数は任意の符号付き整数変数(int、int16など)に受け取ることができます。
    70  符号なし整数は任意の符号なし整数変数に受け取ることができます。
    71  浮動小数点数は任意の浮動小数点数変数に受け取ることができます。
    72  ただし、宛先の変数は値を表現できる必要があります。そうでない場合、デコード操作は失敗します。
    73  
    74  構造体、配列、スライスもサポートされています。構造体はエクスポートされた
    75  フィールドのみをエンコードおよびデコードします。文字列とバイトの配列は、
    76  特別で効率的な表現でサポートされています(下記参照)。スライスがデコードされるとき、
    77  既存のスライスに容量がある場合、スライスはその場で拡張されます。そうでない場合、
    78  新しい配列が割り当てられます。いずれにせよ、結果として得られるスライスの長さは、
    79  デコードされた要素の数を報告します。
    80  
    81  一般的に、割り当てが必要な場合、デコーダはメモリを割り当てます。そうでない場合、
    82  ストリームから読み取った値で宛先の変数を更新します。最初にそれらを初期化することはありません。
    83  したがって、宛先がマップ、構造体、またはスライスなどの複合値である場合、
    84  デコードされた値は要素ごとに既存の変数にマージされます。
    85  
    86  関数とチャネルはgobで送信されません。そのような値をトップレベルでエンコードしようとすると失敗します。
    87  chan型またはfunc型の構造体フィールドは、エクスポートされていないフィールドと全く同じように扱われ、無視されます。
    88  
    89  Gobは、[GobEncoder] または [encoding.BinaryMarshaler] インターフェースを実装する任意の型の値をエンコードできます。
    90  これは、その順序の優先度で対応するメソッドを呼び出すことによって行われます。
    91  
    92  Gobは、[GobDecoder] または [encoding.BinaryUnmarshaler] インターフェースを実装する任意の型の値をデコードできます。
    93  これは、その順序の優先度で対応するメソッドを呼び出すことによって行われます。
    94  
    95  # エンコーディングの詳細
    96  
    97  このセクションでは、ほとんどのユーザーにとって重要でないエンコーディングの詳細を文書化します。
    98  詳細は下から上に提示されます。
    99  
   100  符号なし整数は2つの方法のいずれかで送信されます。それが128未満の場合、その値を持つバイトとして送信されます。
   101  それ以外の場合、それは最小長のビッグエンディアン(高バイト先)バイトストリームとして送信され、
   102  その前にバイト数を保持する1バイトが先行します。このバイト数は否定されます。
   103  したがって、0は(00)として送信され、7は(07)として送信され、256は(FE 01 00)として送信されます。
   104  
   105  ブール値は符号なし整数内にエンコードされます: falseの場合は0、trueの場合は1。
   106  
   107  符号付き整数iは、符号なし整数u内にエンコードされます。u内で、ビット1以上が値を含み、
   108  ビット0は受信時にそれらを補完するかどうかを示します。エンコードアルゴリズムは次のようになります:
   109  
   110  	var u uint
   111  	if i < 0 {
   112  		u = (^uint(i) << 1) | 1 // iを補完し、ビット0を1にします
   113  	} else {
   114  		u = (uint(i) << 1) // iを補完しない、ビット0は0です
   115  	}
   116  	encodeUnsigned(u)
   117  
   118  したがって、低ビットは符号ビットに類似していますが、それを補完ビットにすることで、
   119  最大の負の整数が特別なケースにならないことを保証します。例えば、-129=^128=(^256>>1)は(FE 01 01)としてエンコードされます。
   120  
   121  浮動小数点数は常にfloat64値の表現として送信されます。
   122  その値は [math.Float64bits] を使用してuint64に変換されます。そのuint64は
   123  バイト反転され、通常の符号なし整数として送信されます。バイト反転により、
   124  指数とマンティッサの高精度部分が最初に来ます。低ビットはしばしばゼロなので、
   125  これによりエンコーディングバイトを節約できます。例えば、17.0は
   126  3バイト(FE 31 40)でエンコードされます。
   127  
   128  文字列とバイトのスライスは、符号なしのカウントとその後に続くその値の
   129  未解釈のバイトとして送信されます。
   130  
   131  その他のすべてのスライスと配列は、符号なしのカウントに続いてその要素数だけが
   132  その型の標準的なgobエンコーディングを使用して再帰的に送信されます。
   133  
   134  マップは、符号なしのカウントに続いてその数だけのキー、要素のペアとして送信されます。
   135  空だがnilでないマップは送信されるので、受信者がすでに割り当てていない場合、
   136  送信されたマップがnilでなく、トップレベルでない限り、受信時に常に割り当てられます。
   137  
   138  スライスや配列、マップでは、すべての要素、ゼロ値の要素であっても、
   139  すべての要素がゼロであっても、送信されます。
   140  
   141  構造体は、(フィールド番号、フィールド値)のペアのシーケンスとして送信されます。フィールド
   142  値はその型の標準的なgobエンコーディングを使用して、再帰的に送信されます。フィールドが
   143  その型のゼロ値を持つ場合(配列を除く; 上記参照)、それは伝送から省略されます。フィールド番号は
   144  エンコードされた構造体の型によって定義されます: エンコードされた型の最初のフィールドはフィールド0、
   145  次のフィールドはフィールド1、等です。値をエンコードするとき、フィールド番号は効率のために
   146  デルタエンコードされ、フィールドは常にフィールド番号の増加順に送信されます; したがって、デルタは
   147  符号なしです。デルタエンコーディングの初期化はフィールド番号を-1に設定するので、値が7の符号なし整数フィールド0は
   148  符号なしデルタ=1、符号なし値=7または(01 07)として送信されます。最後に、すべてのフィールドが
   149  送信された後、終端マークが構造体の終わりを示します。そのマークはデルタ=0の
   150  値で、表現は(00)です。
   151  
   152  インターフェース型は互換性がチェックされません。すべてのインターフェース型は、
   153  伝送のために、単一の "interface" 型のメンバーとして扱われます。これはintや[]byteに類似しています。
   154  効果的に、すべてが interface{} として扱われます。インターフェース値は、送信される具体的な型を
   155  識別する文字列として送信されます(この名前は [Register] を呼び出すことで事前に定義する必要があります)。
   156  次に、次のデータの長さのバイト数(値が格納できない場合に値をスキップできるように)、
   157  次にインターフェース値に格納されている具体的(動的)値の通常のエンコーディングが続きます。
   158  (nilのインターフェース値は空の文字列によって識別され、値は送信されません。)
   159  受信時に、デコーダは展開された具体的なアイテムが受信変数のインターフェースを満たしていることを確認します。
   160  
   161  値が [Encoder.Encode] に渡され、その型が構造体(または構造体へのポインタなど)でない場合、
   162  処理の簡便性のために、それは1つのフィールドを持つ構造体として表現されます。
   163  これによる唯一の可視的な効果は、エンコードされた構造体の最後のフィールドの後と同様に、
   164  値の後にゼロバイトをエンコードすることで、デコードアルゴリズムがトップレベルの値が完了したことを知ることができます。
   165  
   166  型の表現については以下に説明します。型が [Encoder] と [Decoder] の間の特定の
   167  接続で定義されると、それには符号付き整数型の
   168  idが割り当てられます。 [Encoder.Encode](v)が呼び出されると、vの型とそのすべての要素に
   169  idが割り当てられていることを確認し、次にペア(typeid, encoded-v)を送信します。
   170  ここで、typeidはvのエンコードされた型の型idであり、encoded-vは値vのgob
   171  エンコーディングです。
   172  
   173  型を定義するために、エンコーダは未使用の正の型idを選択し、
   174  ペア(-type id, encoded-type)を送信します。ここで、encoded-typeはwireType
   175  記述のgobエンコーディングで、これらの型から構築されます:
   176  
   177  	type wireType struct {
   178  		ArrayT           *ArrayType
   179  		SliceT           *SliceType
   180  		StructT          *StructType
   181  		MapT             *MapType
   182  		GobEncoderT      *gobEncoderType
   183  		BinaryMarshalerT *gobEncoderType
   184  		TextMarshalerT   *gobEncoderType
   185  
   186  	}
   187  	type arrayType struct {
   188  		CommonType
   189  		Elem typeId
   190  		Len  int
   191  	}
   192  	type CommonType struct {
   193  		Name string // the name of the struct type
   194  		Id  int    // the id of the type, repeated so it's inside the type
   195  	}
   196  	type sliceType struct {
   197  		CommonType
   198  		Elem typeId
   199  	}
   200  	type structType struct {
   201  		CommonType
   202  		Field []*fieldType // the fields of the struct.
   203  	}
   204  	type fieldType struct {
   205  		Name string // the name of the field.
   206  		Id   int    // the type id of the field, which must be already defined
   207  	}
   208  	type mapType struct {
   209  		CommonType
   210  		Key  typeId
   211  		Elem typeId
   212  	}
   213  	type gobEncoderType struct {
   214  		CommonType
   215  	}
   216  
   217  ネストした型idがある場合、すべての内部型idの型が定義されている必要があります。
   218  これは、トップレベルの型idがencoded-vを記述するために使用される前に行われます。
   219  
   220  設定の簡便性のため、接続はこれらの型をa priori(事前に)理解するように定義されており、
   221  基本的なgob型(int、uintなど)も理解します。それらのidは以下の通りです:
   222  
   223  	bool        1
   224  	int         2
   225  	uint        3
   226  	float       4
   227  	[]byte      5
   228  	string      6
   229  	complex     7
   230  	interface   8
   231  	// gap for reserved ids.
   232  	WireType    16
   233  	ArrayType   17
   234  	CommonType  18
   235  	SliceType   19
   236  	StructType  20
   237  	FieldType   21
   238  	// 22 is slice of fieldType.
   239  	MapType     23
   240  
   241  最後に、Encodeの呼び出しによって作成された各メッセージは、メッセージ内の残りのバイト数の
   242  符号なし整数カウントによって先行します。初期型名の後、インターフェース値は同じように
   243  ラップされます。効果的に、インターフェース値はEncodeの再帰的な呼び出しのように動作します。
   244  
   245  要約すると、gobストリームは次のように見えます
   246  
   247  	(byteCount (-type id, encoding of a wireType)* (type id, encoding of a value))*
   248  
   249  ここで * はゼロ回以上の繰り返しを示し、値の型idは事前に定義されているか、
   250  ストリーム内で値の前に定義されていなければなりません。
   251  
   252  互換性: このパッケージへの将来の変更は、以前のバージョンを使用してエンコードされたストリームとの
   253  互換性を維持するよう努力します。つまり、このパッケージのリリースされたバージョンは、
   254  セキュリティ修正などの問題を除いて、以前にリリースされたバージョンで書かれたデータを
   255  デコードできるはずです。背景についてはGoの互換性ドキュメントを参照してください: https://golang.org/doc/go1compat
   256  
   257  gobワイヤーフォーマットの設計についての議論は「Gobs of data」を参照してください:
   258  https://blog.golang.org/gobs-of-data
   259  
   260  # セキュリティ
   261  
   262  このパッケージは、敵対的な入力に対して強化されるように設計されていませんし、
   263  https://go.dev/security/policy の範囲外です。特に、[Decoder] はデコードされた入力サイズに対して
   264  基本的な健全性チェックのみを行い、その制限は設定可能ではありません。信頼できない
   265  ソースからのgobデータをデコードする際には注意が必要であり、大量のリソースを消費する可能性があります。
   266  */
   267  package gob