?
This document uses PHP Chinese website manual Release
import "encoding/gob"
Overview
Index
Examples
Package gob管理gobs流 - 在編碼器(發(fā)送器)和解碼器(接收器)之間交換的二進制值。一個典型的用途是傳輸遠程過程調(diào)用(RPC)的參數(shù)和結果,如由“net / rpc”包提供的那些。
該實現(xiàn)為流中的每種數(shù)據(jù)類型編譯自定義編解碼器,并且在使用單個編碼器傳輸值流時緩解編譯成本,效率最高。
gob是自我描述的。流中的每個數(shù)據(jù)項都有一個類型的規(guī)范,用一組預定義的類型表示。指針不傳輸,但它們指向的內(nèi)容被傳送; 也就是說,這些值是平坦的。無指針是不允許的,因為它們沒有價值。遞歸類型工作正常,但遞歸值(帶周期的數(shù)據(jù))是有問題的。這可能會改變。
要使用gobs,請創(chuàng)建一個編碼器,并將其與一系列數(shù)據(jù)項一起呈現(xiàn)為值或地址,這些值可以取消引用值。編碼器確保在需要之前發(fā)送所有類型的信息。在接收端,解碼器從編碼流中檢索值并將它們解壓縮成局部變量。
源和目標值/類型不需要完全對應。對于結構體來說,源中但沒有接收變量的域(由名稱標識)將被忽略。在接收變量中但從傳輸類型或值中缺失的字段將在目標中被忽略。如果同時存在兩個同名的字段,則其類型必須兼容。接收器和發(fā)射器都將執(zhí)行所有必要的間接和取消引用,以在gob和實際Go值之間進行轉換。例如,示意性的采空區(qū)類型,
struct { A, B int }
可以從以下任何一種Go類型發(fā)送或接收:
struct { A, B int }// the same*struct { A, B int }// extra indirection of the structstruct { *A, **B int }// extra indirection of the fieldsstruct { A, B int64 }// different concrete value type; see below
它也可以被接收到以下任何一個中:
struct { A, B int }// the samestruct { B, A int }// ordering doesn't matter; matching is by namestruct { A, B, C int }// extra field (C) ignoredstruct { B int }// missing field (A) ignored; data will be droppedstruct { B, C int }// missing field (A) ignored; extra field (C) ignored.
嘗試接收這些類型將導致解碼錯誤:
struct { A int; B uint }// change of signedness for Bstruct { A int; B float }// change of type for Bstruct { }// no field names in commonstruct { C, D int }// no field names in common
整數(shù)以兩種方式傳輸:任意精度有符號整數(shù)或任意精度無符號整數(shù)。gob格式中沒有int8,int16等歧視; 只有有符號和無符號的整數(shù)。如下所述,發(fā)送器以可變長度編碼發(fā)送值; 接收器接受該值并將其存儲在目標變量中。浮點數(shù)總是使用IEEE-754 64位精度發(fā)送(見下文)。
帶符號的整數(shù)可以接收到任何有符號的整數(shù)變量中:int,int16等; 無符號整數(shù)可以接收到任何無符號整數(shù)變量中; 并且可以將浮點值接收到任何浮點變量中。但是,目標變量必須能夠表示值,否則解碼操作將失敗。
結構,數(shù)組和片也被支持。結構僅對導出的字段進行編碼和解碼。字符串和字節(jié)數(shù)組以特殊的高效表示形式提供支持(請參見下文)。當一個片段被解碼時,如果現(xiàn)有片段具有容量,片段將被擴展到位; 如果不是,則分配一個新數(shù)組。無論如何,結果切片的長度報告解碼的元素的數(shù)量。
通常,如果需要分配,解碼器將分配內(nèi)存。如果不是,它將使用從流中讀取的值更新目標變量。它不會首先初始化它們,因此如果目標是復合值(如地圖,結構或切片),則解碼值將按照元素方式合并到現(xiàn)有變量中。
功能和頻道不會以采空區(qū)發(fā)送。試圖在頂層編碼這樣的值將會失敗。chan或func類型的struct字段被視為完全像未導出的字段,并被忽略。
Gob可以按照優(yōu)先順序調(diào)用相應的方法來編碼實現(xiàn)GobEncoder或encoding.BinaryMarshaler接口的任何類型的值。
Gob可以通過調(diào)用相應的方法來解碼實現(xiàn)GobDecoder或編碼的任何類型的值.BinaryUnmarshaler接口也會按照該優(yōu)先順序再次進行解碼。
本節(jié)介紹編碼,對大多數(shù)用戶不重要的詳細信息。細節(jié)從下到上呈現(xiàn)。
無符號整數(shù)以兩種方式之一發(fā)送。如果它小于128,則將其作為具有該值的字節(jié)發(fā)送。否則,它將作為保留該值的最小長度的大端(高字節(jié)的第一個)字節(jié)流發(fā)送,前面是一個保存字節(jié)計數(shù)的字節(jié),取反。因此,0發(fā)送為,7發(fā)送為(07),256發(fā)送為 (FE 01 00)。
布爾值在無符號整數(shù)內(nèi)編碼:0代表假,1代表真。
一個有符號整數(shù)i被編碼在一個無符號整數(shù)u中。在u中,位1向上包含該值; 位0表示它們是否應該在收到時補充。編碼算法如下所示:
var u uintif i < 0 { u = (^uint(i) << 1) | 1 // 補充 i, 位0是1} else { u = (uint(i) << 1) // 不補充 i, 位0是0}encodeUnsigned(u)
低位因此類似于符號位,但是使其成為補碼位而不是保證最大的負整數(shù)不是特例。例如,-129=^128=(^256>>1)編碼為(FE 01 01)。
浮點數(shù)字總是作為float64值的表示形式發(fā)送。該值使用math.Float64bits轉換為uint64。uint64然后被字節(jié)反轉并作為常規(guī)無符號整數(shù)發(fā)送。字節(jié)反轉意味著尾數(shù)的指數(shù)和高精度部分先行。由于低位通常為零,因此可以節(jié)省編碼字節(jié)。例如,17.0只用三個字節(jié)編碼 (FE 31 40)。
字符串和字節(jié)片段作為無符號計數(shù)發(fā)送,然后是該值的許多未解釋的字節(jié)。
所有其他切片和數(shù)組都作為無符號計數(shù)發(fā)送,然后遞歸地使用標準采樣編碼作為其類型。
地圖是作為無符號計數(shù)發(fā)送的,然后是許多鍵元素對??盏牡橇愕牡貓D被發(fā)送,所以如果接收方還沒有分配一個地圖,則一直會在接收時分配一個地圖,除非傳輸?shù)牡貓D是零而不是在頂層。
在切片和陣列以及地圖中,即使所有元素均為零,也會傳輸所有元素,即使是零值元素。
結構以(字段號,字段值)對的序列發(fā)送。字段值是使用遞歸的類型的標準gob編碼發(fā)送的。如果某個字段的類型為零(數(shù)組除外;請參見上文),則該字段在傳輸中將被忽略。字段編號由編碼結構的類型定義:編碼類型的第一個字段是字段0,第二個字段是字段1等。編碼值時,字段編號為delta編碼以提高效率,字段始終按照增加字段的順序發(fā)送; 三角洲因此沒有簽名。增量編碼的初始化將字段編號設置為-1,因此具有值7的無符號整數(shù)字段0作為無符號的增量= 1,無符號的值= 7或(01 07)發(fā)送。最后,在所有字段發(fā)送之后,終止標記表示結構的結束。
接口類型不檢查兼容性; 所有接口類型都作為單個“接口”類型的成員進行處理,類似于int或[] byte - 實際上它們都被視為interface {}。接口值以字符串的形式傳輸,標識發(fā)送的具體類型(必須通過調(diào)用寄存器預先定義的名稱),然后是以下數(shù)據(jù)長度的字節(jié)數(shù)(因此,如果不能存儲),然后是存儲在接口值中的具體(動態(tài))值的通常編碼。(一個零接口值由空字符串標識并且不傳送任何值。)一旦收到,解碼器就會驗證解包后的具體項目是否滿足接收變量的接口。
如果一個值傳遞給Encode,并且該類型不是一個結構體(或指向結構體的指針等),為了簡化處理,它被表示為一個字段的結構。這樣做的唯一可見效果是在值之后編碼一個零字節(jié),就像編碼結構的最后一個字段之后一樣,以便解碼算法知道頂級值何時完成。
類型的表示如下所述。當在編碼器和解碼器之間的給定連接上定義類型時,它被分配一個有符號的整數(shù)類型ID。當調(diào)用Encoder.Encode(v)時,它確保為v及其所有元素的類型分配一個id,然后發(fā)送該對 (typeid, encoded-v),其中typeid是編碼類型的類型id v和encoded-v是值v的gob編碼。
為了定義一個類型,編碼器選擇一個未使用的肯定類型id,并發(fā)送這個對(-type id, encoded-type),其中encoded-type是wireType描述的gob編碼,由以下類型構造而成:
type wireType struct { ArrayT *ArrayType SliceT *SliceType StructT *StructType MapT *MapType}type arrayType struct { CommonType Elem typeId Len int}type CommonType struct { Name string // the name of the struct type Id int // the id of the type, repeated so it's inside the type}type sliceType struct { CommonType Elem typeId}type structType struct { CommonType Field []*fieldType // the fields of the struct.}type fieldType struct { Name string // the name of the field. Id int // the type id of the field, which must be already defined}type mapType struct { CommonType Key typeId Elem typeId}
如果存在嵌套類型標識,則必須在使用頂級類型標識描述encoded-v之前定義所有內(nèi)部類型標識的類型。
為了簡化設置,連接被定義為先驗地理解這些類型,以及基本采樣類型int,uint等。它們的ID是:
bool 1int 2uint 3float 4[]byte 5string 6complex 7interface 8// gap for reserved ids.WireType 16ArrayType 17CommonType 18SliceType 19StructType 20FieldType 21// 22 is slice of fieldType.MapType 23
最后,通過對Encode的調(diào)用創(chuàng)建的每條消息前面都有一個編碼的無符號整數(shù)數(shù)量,該數(shù)量是消息中剩余的字節(jié)數(shù)。在初始類型名稱之后,接口值以相同方式包裝; 實際上,接口值的作用類似于Encode的遞歸調(diào)用。
總之,一個gob流看起來像
(byteCount (-type id, encoding of a wireType)* (type id, encoding of a value))*
其中*表示重復次數(shù)為零或更多,并且值的類型ID必須預先定義或在流中的值之前定義。
兼容性:對軟件包的未來更改將盡力保持與使用先前版本編碼的流的兼容性。也就是說,這個軟件包的任何發(fā)布版本都應該能夠解碼使用任何以前發(fā)布的版本編寫的數(shù)據(jù),并受到諸如安全修復等問題的影響。有關背景信息,請參閱Go兼容性文檔:https://golang.org/doc/go1compat
關于gob線格式的設計討論,請參閱“數(shù)據(jù)采集”:https://blog.golang.org/gobs-of-data
這個例子顯示了軟件包的基本用法:創(chuàng)建一個編碼器,傳輸一些值,用解碼器接收它們。
package mainimport ("bytes""encoding/gob""fmt""log")type P struct { X, Y, Z int Name string}type Q struct { X, Y *int32 Name string}// This example shows the basic usage of the package: Create an encoder,// transmit some values, receive them with a decoder.func main() {// Initialize the encoder and decoder. Normally enc and dec would be// bound to network connections and the encoder and decoder would// run in different processes.var network bytes.Buffer // Stand-in for a network connection enc := gob.NewEncoder(&network) // Will write to network. dec := gob.NewDecoder(&network) // Will read from network.// Encode (send) some values. 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)}// Decode (receive) and print the values.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)}
本示例傳輸一個實現(xiàn)自定義編碼和解碼方法的值。
package mainimport ("bytes""encoding/gob""fmt""log")// The Vector type has unexported fields, which the package cannot access.// We therefore write a BinaryMarshal/BinaryUnmarshal method pair to allow us// to send and receive the type with the gob package. These interfaces are// defined in the "encoding" package.// We could equivalently use the locally defined GobEncode/GobDecoder// interfaces.type Vector struct { x, y, z int}func (v Vector) MarshalBinary() ([]byte, error) {// A simple encoding: plain text.var b bytes.Buffer fmt.Fprintln(&b, v.x, v.y, v.z)return b.Bytes(), nil}// UnmarshalBinary modifies the receiver so it must take a pointer receiver.func (v *Vector) UnmarshalBinary(data []byte) error {// A simple encoding: plain text. b := bytes.NewBuffer(data) _, err := fmt.Fscanln(b, &v.x, &v.y, &v.z)return err}// This example transmits a value that implements the custom encoding and decoding methods.func main() {var network bytes.Buffer // Stand-in for the network.// Create an encoder and send a value. enc := gob.NewEncoder(&network) err := enc.Encode(Vector{3, 4, 5})if err != nil { log.Fatal("encode:", err)}// Create a decoder and receive a value. dec := gob.NewDecoder(&network)var v Vector err = dec.Decode(&v)if err != nil { log.Fatal("decode:", err)} fmt.Println(v)}
此示例顯示如何對接口值進行編碼。與常規(guī)類型的主要區(qū)別在于注冊實現(xiàn)接口的具體類型。
package mainimport ("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}// This example shows how to encode an interface value. The key// distinction from regular types is to register the concrete type that// implements the interface.func main() {var network bytes.Buffer // Stand-in for the network.// We must register the concrete type for the encoder and decoder (which would// normally be on a separate machine from the encoder). On each end, this tells the// engine which concrete type is being sent that implements the interface. gob.Register(Point{})// Create an encoder and send some values. enc := gob.NewEncoder(&network)for i := 1; i <= 3; i++ {interfaceEncode(enc, Point{3 * i, 4 * i})}// Create a decoder and receive some values. dec := gob.NewDecoder(&network)for i := 1; i <= 3; i++ { result := interfaceDecode(dec) fmt.Println(result.Hypotenuse())}}// interfaceEncode encodes the interface value into the encoder.func interfaceEncode(enc *gob.Encoder, p Pythagoras) {// The encode will fail unless the concrete type has been// registered. We registered it in the calling function.// Pass pointer to interface so Encode sees (and hence sends) a value of// interface type. If we passed p directly it would see the concrete type instead.// See the blog post, "The Laws of Reflection" for background. err := enc.Encode(&p)if err != nil { log.Fatal("encode:", err)}}// interfaceDecode decodes the next interface value from the stream and returns it.func interfaceDecode(dec *gob.Decoder) Pythagoras {// The decode will fail unless the concrete type on the wire has been// registered. We registered it in the calling function.var p Pythagoras err := dec.Decode(&p)if err != nil { log.Fatal("decode:", err)}return p}
func Register(value interface{})
func RegisterName(name string, value interface{})
type CommonType
type Decoder
func NewDecoder(r io.Reader) *Decoder
func (dec *Decoder) Decode(e interface{}) error
func (dec *Decoder) DecodeValue(v reflect.Value) error
type Encoder
func NewEncoder(w io.Writer) *Encoder
func (enc *Encoder) Encode(e interface{}) error
func (enc *Encoder) EncodeValue(value reflect.Value) error
type GobDecoder
type GobEncoder
Package (Basic) Package (EncodeDecode) Package (Interface)
dec_helpers.go decode.go decoder.go doc.go enc_helpers.go encode.go encoder.go error.go type.go
func Register(value interface{})
在其內(nèi)部類型名稱下注冊記錄類型,由該類型的值標識。該名稱將標識作為接口變量發(fā)送或接收的值的具體類型。只需要注冊將作為接口值實現(xiàn)傳輸?shù)念愋汀F谕麅H在初始化期間使用,如果類型和名稱之間的映射不是雙向映射,則會發(fā)生混亂。
func RegisterName(name string, value interface{})
RegisterName與Register類似,但使用提供的名稱而不是類型的默認值。
CommonType保存所有類型的元素。它是一個歷史工件,保存為二進制兼容性,并且僅為了包類型描述符的編碼而導出。它不適合客戶直接使用。
type CommonType struct { Name string Id typeId}
解碼器管理從連接的遠程端讀取的類型和數(shù)據(jù)信息的接收。
解碼器只對解碼輸入大小進行基本的理智檢查,并且其限制是不可配置的。解碼來自不受信任來源的gob數(shù)據(jù)時請小心。
type Decoder struct { // contains filtered or unexported fields}
func NewDecoder(r io.Reader) *Decoder
NewDecoder返回一個從io.Reader讀取的新解碼器。如果r不實現(xiàn)io.ByteReader,它將被包裝在一個bufio.Reader中。
func (dec *Decoder) Decode(e interface{}) error
解碼從輸入流中讀取下一個值并將其存儲在由空接口值表示的數(shù)據(jù)中。如果e為零,則該值將被丟棄。否則,e下面的值必須是指向下一個接收數(shù)據(jù)項的正確類型的指針。如果輸入是在EOF,解碼返回io.EOF并且不修改e。
func (dec *Decoder) DecodeValue(v reflect.Value) error
DecodeValue從輸入流中讀取下一個值。如果v是zero reflect.Value(v.Kind()==無效),則DecodeValue丟棄該值。否則,它將值存儲到v中。在這種情況下,v必須表示一個非零指向數(shù)據(jù)的指針,或者是可賦值的reflect.Value(v.CanSet())如果輸入位于EOF,DecodeValue返回io.EOF,不修改v。
編碼器管理類型和數(shù)據(jù)信息傳輸?shù)竭B接的另一端。
type Encoder struct { // contains filtered or unexported fields}
func NewEncoder(w io.Writer) *Encoder
NewEncoder返回一個將在io.Writer上傳輸?shù)男戮幋a器。
func (enc *Encoder) Encode(e interface{}) error
編碼傳輸由空接口值表示的數(shù)據(jù)項,保證所有必需的類型信息先傳送。傳遞一個零指針給編碼器會驚慌,因為它們不能通過gob傳輸。
func (enc *Encoder) EncodeValue(value reflect.Value) error
EncodeValue傳輸由反射值表示的數(shù)據(jù)項,保證所有必要的類型信息都先傳輸完畢。將一個零指針傳遞給EncodeValue將會發(fā)生混亂,因為它們不能通過gob進行傳輸。
GobDecoder是描述數(shù)據(jù)的接口,它提供自己的例程來解碼由GobEncoder發(fā)送的傳輸值。
type GobDecoder interface { // GobDecode overwrites the receiver, which must be a pointer, // with the value represented by the byte slice, which was written // by GobEncode, usually for the same concrete type. GobDecode([]byte) error}
GobEncoder是描述數(shù)據(jù)的接口,它為編碼值提供了自己的表示,以便傳輸給GobDecoder。實現(xiàn)GobEncoder和GobDecoder的類型可以完全控制其數(shù)據(jù)的表示,因此可能包含私有字段,通道和函數(shù),這些通常不會在gob流中傳輸。
注意:由于gobs可以永久保存,因此確保GobEncoder使用的編碼在軟件變化時保持穩(wěn)定是一個很好的設計。例如,GobEncode在編碼中包含一個版本號可能是有意義的。
type GobEncoder interface { // GobEncode returns a byte slice representing the encoding of the // receiver for transmission to a GobDecoder, usually of the same // concrete type. GobEncode() ([]byte, error)}