mirror of https://github.com/golang/go.git
encoding/gob: add examples
Also tweak the package document, putting in section headings and adding a sentence about intended use. Fixes #4925. R=golang-dev, iant, adg, ugorji CC=golang-dev https://golang.org/cl/14519044
This commit is contained in:
parent
cf694aac34
commit
daa61d1eb3
|
|
@ -8,6 +8,12 @@ Encoder (transmitter) and a Decoder (receiver). A typical use is transporting
|
||||||
arguments and results of remote procedure calls (RPCs) such as those provided by
|
arguments and results of remote procedure calls (RPCs) such as those provided by
|
||||||
package "rpc".
|
package "rpc".
|
||||||
|
|
||||||
|
The implementation compiles a custom codec for each data type in the stream and
|
||||||
|
is most efficient when a single Encoder is used to transmit a stream of values,
|
||||||
|
amortizing the cost of compilation.
|
||||||
|
|
||||||
|
Basics
|
||||||
|
|
||||||
A stream of gobs is self-describing. Each data item in the stream is preceded by
|
A stream of gobs is self-describing. Each data item in the stream is preceded by
|
||||||
a specification of its type, expressed in terms of a small set of predefined
|
a specification of its type, expressed in terms of a small set of predefined
|
||||||
types. Pointers are not transmitted, but the things they point to are
|
types. Pointers are not transmitted, but the things they point to are
|
||||||
|
|
@ -20,6 +26,8 @@ all type information is sent before it is needed. At the receive side, a
|
||||||
Decoder retrieves values from the encoded stream and unpacks them into local
|
Decoder retrieves values from the encoded stream and unpacks them into local
|
||||||
variables.
|
variables.
|
||||||
|
|
||||||
|
Types and Values
|
||||||
|
|
||||||
The source and destination values/types need not correspond exactly. For structs,
|
The source and destination values/types need not correspond exactly. For structs,
|
||||||
fields (identified by name) that are in the source but absent from the receiving
|
fields (identified by name) that are in the source but absent from the receiving
|
||||||
variable will be ignored. Fields that are in the receiving variable but missing
|
variable will be ignored. Fields that are in the receiving variable but missing
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package gob_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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 Example_gob_encode_decode() {
|
||||||
|
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)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// {3 4 5}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 Example_interface() {
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 5
|
||||||
|
// 10
|
||||||
|
// 15
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// This example shows the basic usage of the package: Create an encoder,
|
||||||
|
// transmit some values, receive them with a decoder.
|
||||||
|
func Example_basic() {
|
||||||
|
// 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)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// "Pythagoras": {3, 4}
|
||||||
|
// "Treehouse": {1782, 1841}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue