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