]> Cypherpunks repositories - gostls13.git/commitdiff
encoding/gob: add examples
authorRob Pike <r@golang.org>
Tue, 8 Oct 2013 20:13:40 +0000 (13:13 -0700)
committerRob Pike <r@golang.org>
Tue, 8 Oct 2013 20:13:40 +0000 (13:13 -0700)
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

src/pkg/encoding/gob/doc.go
src/pkg/encoding/gob/example_encdec_test.go [new file with mode: 0644]
src/pkg/encoding/gob/example_interface_test.go [new file with mode: 0644]
src/pkg/encoding/gob/example_test.go [new file with mode: 0644]

index 48b6742315b4231d75a3ba58de3bc29d02bdc3a3..28f0c05a5c5fdc3d919f8fa7b29eec95f02ac98f 100644 (file)
@@ -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
 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 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
@@ -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
 variables.
 
+Types and Values
+
 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
 variable will be ignored.  Fields that are in the receiving variable but missing
diff --git a/src/pkg/encoding/gob/example_encdec_test.go b/src/pkg/encoding/gob/example_encdec_test.go
new file mode 100644 (file)
index 0000000..0ae6d9d
--- /dev/null
@@ -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}
+}
diff --git a/src/pkg/encoding/gob/example_interface_test.go b/src/pkg/encoding/gob/example_interface_test.go
new file mode 100644 (file)
index 0000000..4681e63
--- /dev/null
@@ -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
+}
diff --git a/src/pkg/encoding/gob/example_test.go b/src/pkg/encoding/gob/example_test.go
new file mode 100644 (file)
index 0000000..020352c
--- /dev/null
@@ -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}
+}