Commit daa61d1e authored by Rob Pike's avatar Rob Pike

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
parent cf694aac
...@@ -8,6 +8,12 @@ Encoder (transmitter) and a Decoder (receiver). A typical use is transporting ...@@ -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 ...@@ -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
......
// 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}
}
// 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
}
// 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}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment