[インデックス 17220] ファイルの概要
このコミットは、Go言語の encoding/gob
パッケージが、Go 1.2で導入された encoding
パッケージ内の新しい汎用インターフェース(encoding.BinaryMarshaler
, encoding.BinaryUnmarshaler
, encoding.TextMarshaler
, encoding.TextUnmarshaler
)をサポートするように拡張するものです。これにより、gob
エンコーディング/デコーディングにおいて、より多様な型がカスタムシリアライズ/デシリアライズロジックを提供できるようになります。
コミット
commit ce3ba126a0c5370c2c4c4e1ef32291316b96b5b0
Author: Russ Cox <rsc@golang.org>
Date: Wed Aug 14 00:18:48 2013 -0400
encoding/gob: support new generic interfaces in package encoding
R=r
CC=golang-dev
https://golang.org/cl/12681044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/ce3ba126a0c5370c2c4c4e1ef32291316b96b5b0
元コミット内容
encoding/gob: support new generic interfaces in package encoding
R=r
CC=golang-dev
https://golang.org/cl/12681044
変更の背景
Go言語の encoding
パッケージは、様々なデータ形式(JSON, XML, Gobなど)間でデータを変換するための標準的なインターフェースを提供します。このコミットが行われた2013年当時、Go 1.2のリリースに向けて、encoding.BinaryMarshaler
/BinaryUnmarshaler
および encoding.TextMarshaler
/TextUnmarshaler
といった、より汎用的なデータ変換インターフェースが導入されつつありました。
encoding/gob
はGo独自のバイナリシリアライゼーション形式であり、Goプログラム間で構造化されたデータを効率的に送受信するために設計されています。これまで gob
は、カスタムエンコーディング/デコーディングのために GobEncoder
および GobDecoder
という独自のインターフェースをサポートしていました。
この変更の背景には、Goのエコシステム全体でデータ変換の統一性を高めるという目的があります。新しい汎用インターフェースを gob
がサポートすることで、開発者は gob
だけでなく、他の encoding
パッケージ(例: encoding/json
)でも同じカスタムシリアライゼーションロジックを再利用できるようになります。これにより、コードの重複を減らし、より柔軟なデータ処理が可能になります。
具体的には、gob
がこれらの新しいインターフェースを認識し、既存の GobEncoder
/GobDecoder
と同様に、型のカスタムエンコーディング/デコーディングを処理できるようにすることが目的です。これにより、gob
の利用者は、gob
固有のインターフェースだけでなく、より広範な encoding
パッケージのインターフェースを利用して、自身の型をシリアライズ/デシリアライズできるようになります。
前提知識の解説
Go言語の encoding/gob
パッケージ
encoding/gob
は、Go言語のプログラム間でGoのデータ構造をエンコードおよびデコードするためのバイナリシリアライゼーション形式です。主な特徴は以下の通りです。
- 自己記述的:
gob
ストリームは、データだけでなく、そのデータの型情報も含まれています。これにより、受信側は事前に型を知らなくてもデータをデコードできます。 - 効率性: バイナリ形式であるため、JSONやXMLなどのテキストベースの形式よりもコンパクトで高速です。
- Go固有: Goの型システムに密接に統合されており、構造体、スライス、マップ、プリミティブ型などを直接エンコード/デコードできます。
- カスタムエンコーディング:
GobEncoder
およびGobDecoder
インターフェースを実装することで、型は自身のエンコード/デコード方法をカスタマイズできます。
GobEncoder
および GobDecoder
インターフェース
encoding/gob
パッケージは、カスタムシリアライゼーションを可能にするために以下のインターフェースを定義しています。
type GobEncoder interface {
GobEncode() ([]byte, error)
}
type GobDecoder interface {
GobDecode([]byte) error
}
これらのインターフェースを型が実装している場合、gob
はその型のデフォルトのシリアライゼーションロジックではなく、GobEncode
または GobDecode
メソッドを呼び出してデータの変換を行います。
Go言語の encoding
パッケージと汎用インターフェース
Go 1.2で導入された encoding
パッケージは、より汎用的なデータ変換インターフェースを提供します。これらは、特定のエンコーディング形式に依存しない、データ表現の標準化を目指しています。
encoding.BinaryMarshaler
および encoding.BinaryUnmarshaler
バイナリ形式でのカスタムシリアライゼーション/デシリアライゼーションを定義するためのインターフェースです。
type BinaryMarshaler interface {
MarshalBinary() ([]byte, error)
}
type BinaryUnmarshaler interface {
UnmarshalBinary([]byte) error
}
これらのインターフェースは、型が自身をバイナリ形式に変換する方法、またはバイナリデータから自身を再構築する方法を定義するために使用されます。
encoding.TextMarshaler
および encoding.TextUnmarshaler
テキスト形式でのカスタムシリアライゼーション/デシリアライゼーションを定義するためのインターフェースです。
type TextMarshaler interface {
MarshalText() ([]byte, error)
}
type TextUnmarshaler interface {
UnmarshalText([]byte) error
}
これらのインターフェースは、型が自身をテキスト形式に変換する方法、またはテキストデータから自身を再構築する方法を定義するために使用されます。例えば、fmt.Stringer
とは異なり、これはデータ変換に特化しています。
技術的詳細
このコミットの技術的詳細は、encoding/gob
パッケージがどのようにして新しい汎用 encoding
インターフェースを認識し、処理するように変更されたかにあります。
-
userTypeInfo
構造体の拡張:src/pkg/encoding/gob/type.go
にあるuserTypeInfo
構造体は、Goの型に関するメタデータを保持します。このコミットでは、isGobEncoder
とisGobDecoder
フィールドが削除され、代わりにexternalEnc
とexternalDec
という新しいフィールドが追加されました。これらは、型がどの外部エンコーディング/デコーディングインターフェース(GobEncoder
,BinaryMarshaler
,TextMarshaler
)を実装しているかを示す整数値(ビットフラグ)として機能します。type userTypeInfo struct { // ... (既存フィールド) externalEnc int // xGob, xBinary, or xText externalDec int // xGob, xBinary or xText // ... (既存フィールド) } // externalEncoding bits const ( xGob = 1 + iota // GobEncoder or GobDecoder xBinary // encoding.BinaryMarshaler or encoding.BinaryUnmarshaler xText // encoding.TextMarshaler or encoding.TextUnmarshaler )
validUserType
関数内で、reflect.Type
がこれらの新しいインターフェースを実装しているかどうかがチェックされ、対応するxGob
,xBinary
,xText
の値がexternalEnc
またはexternalDec
に設定されます。 -
エンコーディングロジックの変更 (
encode.go
):encodeGobEncoder
関数は、GobEncoder
インターフェースを実装する型のエンコーディングを処理していましたが、このコミットにより、ut.externalEnc
の値に基づいてGobEncoder
,BinaryMarshaler
,TextMarshaler
のいずれかのメソッドを呼び出すように変更されました。func (enc *Encoder) encodeGobEncoder(b *bytes.Buffer, ut *userTypeInfo, v reflect.Value) { var data []byte var err error switch ut.externalEnc { case xGob: data, err = v.Interface().(GobEncoder).GobEncode() case xBinary: data, err = v.Interface().(encoding.BinaryMarshaler).MarshalBinary() case xText: data, err = v.Interface().(encoding.TextMarshaler).MarshalText() } // ... (エラーハンドリングとデータ書き込み) }
また、
encOpFor
やcompileEnc
などの関数も、型のエンコーディング方法を決定する際にut.isGobEncoder
の代わりにut.externalEnc != 0
をチェックするように更新されました。 -
デコーディングロジックの変更 (
decode.go
):decodeGobDecoder
関数も同様に、GobDecoder
インターフェースを実装する型のデコーディングを処理していましたが、ut.externalDec
の値に基づいてGobDecoder
,BinaryUnmarshaler
,TextUnmarshaler
のいずれかのメソッドを呼び出すように変更されました。func (dec *Decoder) decodeGobDecoder(ut *userTypeInfo, state *decoderState, v reflect.Value) { // ... (データ読み込み) switch ut.externalDec { case xGob: err = v.Interface().(GobDecoder).GobDecode(b) case xBinary: err = v.Interface().(encoding.BinaryUnmarshaler).UnmarshalBinary(b) case xText: err = v.Interface().(encoding.TextUnmarshaler).UnmarshalText(b) } // ... (エラーハンドリング) }
decOpFor
やcompatibleType
などの関数も、型のデコーディング方法を決定する際にut.isGobDecoder
の代わりにut.externalDec != 0
をチェックするように更新されました。 -
型情報の伝達 (
type.go
,debug.go
):gob
は、エンコード/デコード時に型情報を交換します。このコミットでは、wireType
構造体にBinaryMarshalerT
とTextMarshalerT
フィールドが追加され、これらの新しいインターフェースを実装する型がgob
ストリーム内で適切に識別されるようになりました。type wireType struct { // ... (既存フィールド) GobEncoderT *gobEncoderType BinaryMarshalerT *gobEncoderType // New TextMarshalerT *gobEncoderType // New }
debug.go
のtypeDefinition
関数も、これらの新しいwireType
フィールドを処理するように更新され、デバッグ情報が正しく表示されるようになりました。 -
ドキュメントの更新 (
doc.go
):src/pkg/encoding/gob/doc.go
のドキュメントが更新され、gob
がencoding.BinaryMarshaler
,encoding.TextMarshaler
およびそれらのUnmarshaler
インターフェースをサポートすることが明記されました。これにより、ユーザーはこれらの新しい機能について知ることができます。 -
テストの追加/更新 (
gobencdec_test.go
):src/pkg/encoding/gob/gobencdec_test.go
には、BinaryGobber
,TextGobber
などの新しいテスト型が追加され、これらの型がBinaryMarshaler
/Unmarshaler
およびTextMarshaler
/Unmarshaler
インターフェースを実装していることを確認するテストケースが追加されました。これにより、新しい機能が正しく動作することが保証されます。
これらの変更により、encoding/gob
はGoの標準 encoding
インターフェースとの互換性を高め、より柔軟なデータシリアライゼーション/デシリアライゼーションの選択肢を開発者に提供するようになりました。
コアとなるコードの変更箇所
src/pkg/encoding/gob/decode.go
--- a/src/pkg/encoding/gob/decode.go
+++ b/src/pkg/encoding/gob/decode.go
@@ -767,15 +768,22 @@ func (dec *Decoder) ignoreInterface(state *decoderState) {
// decodeGobDecoder decodes something implementing the GobDecoder interface.
// The data is encoded as a byte slice.
-func (dec *Decoder) decodeGobDecoder(state *decoderState, v reflect.Value) {
+func (dec *Decoder) decodeGobDecoder(ut *userTypeInfo, state *decoderState, v reflect.Value) {
// Read the bytes for the value.
b := make([]byte, state.decodeUint())
_, err := state.b.Read(b)
if err != nil {
error_(err)
}
- // We know it's a GobDecoder, so just call the method directly.
- err = v.Interface().(GobDecoder).GobDecode(b)
+ // We know it's one of these.
+ switch ut.externalDec {
+ case xGob:
+ err = v.Interface().(GobDecoder).GobDecode(b)
+ case xBinary:
+ err = v.Interface().(encoding.BinaryUnmarshaler).UnmarshalBinary(b)
+ case xText:
+ err = v.Interface().(encoding.TextUnmarshaler).UnmarshalText(b)
+ }
if err != nil {
error_(err)
}
@@ -825,9 +833,10 @@ var decIgnoreOpMap = map[typeId]decOp{
func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProgress map[reflect.Type]*decOp) (*decOp, int) {
ut := userType(rt)
// If the type implements GobEncoder, we handle it without further processing.
- if ut.isGobDecoder {
+ if ut.externalDec != 0 {
return dec.gobDecodeOpFor(ut)
}
+
// If this type is already in progress, it's a recursive type (e.g. map[string]*T).
// Return the pointer to the op we're already building.
if opPtr := inProgress[rt]; opPtr != nil {
@@ -954,7 +963,7 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp {
}
-\t\tcase wire.GobEncoderT != nil:\
+\t\tcase wire.GobEncoderT != nil, wire.BinaryMarshalerT != nil, wire.TextMarshalerT != nil:\
op = func(i *decInstr, state *decoderState, p unsafe.Pointer) {
state.dec.ignoreGobDecoder(state)
}
@@ -993,7 +1002,7 @@ func (dec *Decoder) gobDecodeOpFor(ut *userTypeInfo) (*decOp, int) {
} else {
v = reflect.NewAt(rcvrType, p).Elem()
}
-\t\tstate.dec.decodeGobDecoder(state, v)\
+\t\tstate.dec.decodeGobDecoder(ut, state, v)\
}\
return &op, int(ut.indir)\
@@ -1010,12 +1019,18 @@ func (dec *Decoder) compatibleType(fr reflect.Type, fw typeId, inProgress map[re\
inProgress[fr] = fw
ut := userType(fr)
wire, ok := dec.wireType[fw]
- // If fr is a GobDecoder, the wire type must be GobEncoder.
- // And if fr is not a GobDecoder, the wire type must not be either.
- if ut.isGobDecoder != (ok && wire.GobEncoderT != nil) { // the parentheses look odd but are correct.
+ // If wire was encoded with an encoding method, fr must have that method.
+ // And if not, it must not.
+ // At most one of the booleans in ut is set.
+ // We could possibly relax this constraint in the future in order to
+ // choose the decoding method using the data in the wireType.
+ // The parentheses look odd but are correct.
+ if (ut.externalDec == xGob) != (ok && wire.GobEncoderT != nil) ||
+ (ut.externalDec == xBinary) != (ok && wire.BinaryMarshalerT != nil) ||
+ (ut.externalDec == xText) != (ok && wire.TextMarshalerT != nil) {
return false
}
-\tif ut.isGobDecoder { // This test trumps all others.\
+\tif ut.externalDec != 0 { // This test trumps all others.\
return true
}\
switch t := ut.base; t.Kind() {
@@ -1114,8 +1129,7 @@ func (dec *Decoder) compileIgnoreSingle(remoteId typeId) (engine *decEngine, err\
func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEngine, err error) {
rt := ut.base
srt := rt
-\tif srt.Kind() != reflect.Struct ||\
-\t\tut.isGobDecoder {\
+\tif srt.Kind() != reflect.Struct || ut.externalDec != 0 {\
return dec.compileSingle(remoteId, ut)
}
var wireStruct *structType
@@ -1223,7 +1237,7 @@ func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) {
return
}
engine := *enginePtr
-\tif st := base; st.Kind() == reflect.Struct && !ut.isGobDecoder {\
+\tif st := base; st.Kind() == reflect.Struct && ut.externalDec == 0 {\
if engine.numInstr == 0 && st.NumField() > 0 && len(dec.wireType[wireId].StructT.Field) > 0 {
name := base.Name()
errorf("type mismatch: no fields matched compiling decoder for %s", name)
src/pkg/encoding/gob/type.go
--- a/src/pkg/encoding/gob/type.go
+++ b/src/pkg/encoding/gob/type.go
@@ -18,14 +19,21 @@ import (
// to the package. It's computed once and stored in a map keyed by reflection
// type.
type userTypeInfo struct {
-\tuser reflect.Type // the type the user handed us
-\tbase reflect.Type // the base type after all indirections
-\tindir int // number of indirections to reach the base type
-\tisGobEncoder bool // does the type implement GobEncoder?
-\tisGobDecoder bool // does the type implement GobDecoder?
-\tencIndir int8 // number of indirections to reach the receiver type; may be negative
-\tdecIndir int8 // number of indirections to reach the receiver type; may be negative
-}\
+\tuser reflect.Type // the type the user handed us
+\tbase reflect.Type // the base type after all indirections
+\tindir int // number of indirections to reach the base type
+\texternalEnc int // xGob, xBinary, or xText
+\texternalDec int // xGob, xBinary or xText
+\tencIndir int8 // number of indirections to reach the receiver type; may be negative
+\tdecIndir int8 // number of indirections to reach the receiver type; may be negative
+}\
+
+// externalEncoding bits
+const (
+\txGob = 1 + iota // GobEncoder or GobDecoder
+\txBinary // encoding.BinaryMarshaler or encoding.BinaryUnmarshaler
+\txText // encoding.TextMarshaler or encoding.TextUnmarshaler
+)\
var (\
\t// Protected by an RWMutex because we read it a lot and write
@@ -75,15 +83,34 @@ func validUserType(rt reflect.Type) (ut *userTypeInfo, err error) {
\t\t}\
\t\tut.indir++\
\t}\
-\tut.isGobEncoder, ut.encIndir = implementsInterface(ut.user, gobEncoderInterfaceType)\
-\tut.isGobDecoder, ut.decIndir = implementsInterface(ut.user, gobDecoderInterfaceType)\
+\
+\tif ok, indir := implementsInterface(ut.user, gobEncoderInterfaceType); ok {
+\t\tut.externalEnc, ut.encIndir = xGob, indir
+\t} else if ok, indir := implementsInterface(ut.user, binaryMarshalerInterfaceType); ok {
+\t\tut.externalEnc, ut.encIndir = xBinary, indir
+\t} else if ok, indir := implementsInterface(ut.user, textMarshalerInterfaceType); ok {
+\t\tut.externalEnc, ut.encIndir = xText, indir
+\t}\
+\
+\tif ok, indir := implementsInterface(ut.user, gobDecoderInterfaceType); ok {
+\t\tut.externalDec, ut.decIndir = xGob, indir
+\t} else if ok, indir := implementsInterface(ut.user, binaryUnmarshalerInterfaceType); ok {
+\t\tut.externalDec, ut.decIndir = xBinary, indir
+\t} else if ok, indir := implementsInterface(ut.user, textUnmarshalerInterfaceType); ok {
+\t\tut.externalDec, ut.decIndir = xText, indir
+\t}\
+\
\tuserTypeCache[rt] = ut
\treturn
}\
var (\
-\tgobEncoderInterfaceType = reflect.TypeOf((*GobEncoder)(nil)).Elem()\
-\tgobDecoderInterfaceType = reflect.TypeOf((*GobDecoder)(nil)).Elem()\
+\tgobEncoderInterfaceType = reflect.TypeOf((*GobEncoder)(nil)).Elem()\
+\tgobDecoderInterfaceType = reflect.TypeOf((*GobDecoder)(nil)).Elem()\
+\tbinaryMarshalerInterfaceType = reflect.TypeOf((*encoding.BinaryMarshaler)(nil)).Elem()\
+\tbinaryUnmarshalerInterfaceType = reflect.TypeOf((*encoding.BinaryUnmarshaler)(nil)).Elem()\
+\ttextMarshalerInterfaceType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()\
+\ttextUnmarshalerInterfaceType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()\
)\
// implementsInterface reports whether the type implements the
@@ -593,11 +620,13 @@ func bootstrapType(name string, e interface{}, expect typeId) typeId {
// To maintain binary compatibility, if you extend this type, always put
// the new fields last.
type wireType struct {
-\tArrayT *arrayType
-\tSliceT *sliceType
-\tStructT *structType
-\tMapT *mapType
-\tGobEncoderT *gobEncoderType
+\tArrayT *arrayType
+\tSliceT *sliceType
+\tStructT *structType
+\tMapT *mapType
+\tGobEncoderT *gobEncoderType
+\tBinaryMarshalerT *gobEncoderType
+\tTextMarshalerT *gobEncoderType
}\
func (w *wireType) string() string {
@@ -631,12 +660,20 @@ var typeInfoMap = make(map[reflect.Type]*typeInfo) // protected by typeLock
// typeLock must be held.
func getTypeInfo(ut *userTypeInfo) (*typeInfo, error) {
\trt := ut.base
-\tif ut.isGobEncoder {\
+\tif ut.externalEnc != 0 {\
\t\t// We want the user type, not the base type.\
\t\trt = ut.user\
\t}\
\tif _, alreadySent := enc.sent[rt]; !alreadySent {\
\t\t// ... (既存ロジック)
\t}\
-\tif ut.isGobEncoder {\
+\tif ut.externalEnc != 0 {\
\t\tuserType, err := getType(rt.Name(), ut, rt)\
\t\tif err != nil {\
\t\t\treturn nil, err\
\t\t}\
-\t\tinfo.wire = &wireType{GobEncoderT: userType.id().gobType().(*gobEncoderType)}\
+\t\tgt := userType.id().gobType().(*gobEncoderType)\
+\t\tswitch ut.externalEnc {\
+\t\tcase xGob:\
+\t\t\tinfo.wire = &wireType{GobEncoderT: gt}\
+\t\tcase xBinary:\
+\t\t\tinfo.wire = &wireType{BinaryMarshalerT: gt}\
+\t\tcase xText:\
+\t\t\tinfo.wire = &wireType{TextMarshalerT: gt}\
+\t\t}\
\t\ttypeInfoMap[ut.user] = info
\t\treturn info, nil
\t}\
コアとなるコードの解説
src/pkg/encoding/gob/decode.go
の変更点
-
decodeGobDecoder
関数のシグネチャ変更とロジック拡張:- 変更前:
func (dec *Decoder) decodeGobDecoder(state *decoderState, v reflect.Value)
- 変更後:
func (dec *Decoder) decodeGobDecoder(ut *userTypeInfo, state *decoderState, v reflect.Value)
userTypeInfo
(ut
) パラメータが追加され、デコード対象の型がどの外部インターフェースを実装しているか(xGob
,xBinary
,xText
)をut.externalDec
を通じて判断できるようになりました。switch ut.externalDec
文が導入され、GobDecoder
,encoding.BinaryUnmarshaler
,encoding.TextUnmarshaler
のいずれかのメソッドを動的に呼び出すようになりました。これにより、gob
はこれらの新しいインターフェースを実装する型を適切にデコードできます。
- 変更前:
-
decOpFor
関数の条件変更:- 変更前:
if ut.isGobDecoder { ... }
- 変更後:
if ut.externalDec != 0 { ... }
- 型が
GobDecoder
を実装しているかどうかのチェックが、いずれかの外部デコーディングインターフェースを実装しているかどうかのチェックに汎用化されました。
- 変更前:
-
decIgnoreOpFor
関数の条件変更:- 変更前:
case wire.GobEncoderT != nil:
- 変更後:
case wire.GobEncoderT != nil, wire.BinaryMarshalerT != nil, wire.TextMarshalerT != nil:
gob
ストリーム内の型情報(wireType
)が、GobEncoderT
だけでなく、新しく追加されたBinaryMarshalerT
やTextMarshalerT
を持っている場合も、カスタムデコーディングロジックを無視する(スキップする)ように変更されました。これは、エンコード時にカスタムエンコーダが使用された場合、デコード時も対応するカスタムデコーダで処理されるべきであり、通常の構造体デコードロジックは適用されないためです。
- 変更前:
-
compatibleType
関数の条件変更:- 変更前は
ut.isGobDecoder
とwire.GobEncoderT
の関係のみをチェックしていましたが、変更後はut.externalDec
とwire.GobEncoderT
,wire.BinaryMarshalerT
,wire.TextMarshalerT
のそれぞれの組み合わせを厳密にチェックするようになりました。これにより、エンコードされた型とデコードされる型が、どのカスタムインターフェースを使用しているかについて互換性があることを保証します。
- 変更前は
-
compileDec
およびdecodeValue
関数の条件変更:- これらの関数も、構造体のコンパイルや値のデコードを行う際に、
ut.isGobDecoder
の代わりにut.externalDec != 0
を使用して、型がカスタムデコーディングインターフェースを実装しているかどうかを判断するように変更されました。
- これらの関数も、構造体のコンパイルや値のデコードを行う際に、
src/pkg/encoding/gob/type.go
の変更点
-
userTypeInfo
構造体の定義変更:isGobEncoder
とisGobDecoder
ブール値フィールドが削除され、代わりにexternalEnc
とexternalDec
という整数値フィールドが追加されました。xGob
,xBinary
,xText
という定数が定義され、externalEnc
/externalDec
がこれらの値を取ることで、型がどのエンコーディング/デコーディングインターフェースを実装しているかを示すようになりました。
-
validUserType
関数のロジック変更:implementsInterface
関数を使用して、GobEncoder
,GobDecoder
に加えて、encoding.BinaryMarshaler
,encoding.BinaryUnmarshaler
,encoding.TextMarshaler
,encoding.TextUnmarshaler
の各インターフェースを型が実装しているかをチェックするようになりました。- 実装しているインターフェースに応じて、
ut.externalEnc
またはut.externalDec
に対応する定数(xGob
,xBinary
,xText
)を設定します。優先順位はGobEncoder/Decoder
->BinaryMarshaler/Unmarshaler
->TextMarshaler/Unmarshaler
の順です。
-
新しいインターフェース型の定義:
binaryMarshalerInterfaceType
,binaryUnmarshalerInterfaceType
,textMarshalerInterfaceType
,textUnmarshalerInterfaceType
というreflect.Type
変数が追加され、これらのインターフェースの型情報を保持するようになりました。これらはimplementsInterface
関数でインターフェースの実装チェックを行う際に使用されます。
-
wireType
構造体の定義変更:BinaryMarshalerT
とTextMarshalerT
という新しいフィールドが追加されました。これにより、gob
ストリーム内で、型がBinaryMarshaler
またはTextMarshaler
を実装していることを示す型情報を伝達できるようになりました。
-
getTypeInfo
関数のロジック変更:- 型情報マップに登録する際に、
ut.isGobEncoder
の代わりにut.externalEnc != 0
を使用して、型がカスタムエンコーディングインターフェースを実装しているかどうかを判断するようになりました。 info.wire
の設定時に、ut.externalEnc
の値に基づいてGobEncoderT
,BinaryMarshalerT
,TextMarshalerT
のいずれかをwireType
に設定するようになりました。
- 型情報マップに登録する際に、
これらの変更は、encoding/gob
がGoの標準 encoding
インターフェースを透過的に扱えるようにするための基盤を構築しています。
関連リンク
- Go 1.2 Release Notes: https://go.dev/doc/go1.2 (特に "The encoding packages" セクション)
encoding
package documentation: https://pkg.go.dev/encodingencoding/gob
package documentation: https://pkg.go.dev/encoding/gob
参考にした情報源リンク
- https://go.dev/doc/go1.2
- https://pkg.go.dev/encoding
- https://pkg.go.dev/encoding/gob
- コミットハッシュ:
ce3ba126a0c5370c2c4c4e1ef32291316b96b5b0
(GitHub) - Go CL 12681044: https://golang.org/cl/12681044 (Goのコードレビューシステム)