# 用 Gob 传输数据

Gob 是 Go 自己的以二进制形式序列化和反序列化程序数据的格式；可以在 `encoding` 包中找到。这种格式的数据简称为 Gob （即 Go binary 的缩写）。类似于 Python 的 "pickle" 和 Java 的 "Serialization"。

Gob 通常用于远程方法调用（RPCs，参见 15.9 的 rpc 包）参数和结果的传输，以及应用程序和机器之间的数据传输。 它和 JSON 或 XML 有什么不同呢？Gob 特定地用于纯 Go 的环境中，例如，两个用 Go 写的服务之间的通信。这样的话服务可以被实现得更加高效和优化。 Gob 不是可外部定义，语言无关的编码方式。因此它的首选格式是二进制，而不是像 JSON 和 XML 那样的文本格式。 Gob 并不是一种不同于 Go 的语言，而是在编码和解码过程中用到了 Go 的反射。

Gob 文件或流是完全自描述的：里面包含的所有类型都有一个对应的描述，并且总是可以用 Go 解码，而不需要了解文件的内容。

只有可导出的字段会被编码，零值会被忽略。在解码结构体的时候，只有同时匹配名称和可兼容类型的字段才会被解码。当源数据类型增加新字段后，Gob 解码客户端仍然可以以这种方式正常工作：解码客户端会继续识别以前存在的字段。并且还提供了很大的灵活性，比如在发送者看来，整数被编码成没有固定长度的可变长度，而忽略具体的 Go 类型。

假如在发送者这边有一个有结构 T：

```go
type T struct { X, Y, Z int }
var t = T{X: 7, Y: 0, Z: 8}
```

而在接收者这边可以用一个结构体 U 类型的变量 u 来接收这个值：

```go
type U struct { X, Y *int8 }
var u U
```

在接收者中，X 的值是7，Y 的值是0（Y的值并没有从 t 中传递过来，因为它是零值）

和 JSON 的使用方式一样，Gob 使用通用的 `io.Writer` 接口，通过 `NewEncoder()` 函数创建 `Encoder` 对象并调用 `Encode()`；相反的过程使用通用的 `io.Reader` 接口，通过 `NewDecoder()` 函数创建 `Decoder` 对象并调用 `Decode`。

我们把示例 12.12 的信息写进名为 vcard.gob 的文件作为例子。这会产生一个文本可读数据和二进制数据的混合，当你试着在文本编辑中打开的时候会看到。

在示例 12.18 中你会看到一个编解码，并且以字节缓冲模拟网络传输的简单例子：

示例 12.18 [gob1.go](https://github.com/yangchuansheng/the-way-to-go_ZH_CN/tree/f30ab7d8c58f85840a0afb548024b93642b518d5/eBook/examples/chapter_12/gob1.go)：

```go
// gob1.go
package main

import (
    "bytes"
    "fmt"
    "encoding/gob"
    "log"
)

type P struct {
    X, Y, Z int
    Name    string
}

type Q struct {
    X, Y *int32
    Name string
}

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) the value.      
    err := enc.Encode(P{3, 4, 5, "Pythagoras"})
    if err != nil {
        log.Fatal("encode error:", err)
    }
    // Decode (receive) the value.      
    var q Q
    err = dec.Decode(&q)
    if err != nil {
        log.Fatal("decode error:", err)
    }
    fmt.Printf("%q: {%d,%d}\n", q.Name, *q.X, *q.Y)
}
// Output:   "Pythagoras": {3,4}
```

示例 12.19 [gob2.go](https://github.com/yangchuansheng/the-way-to-go_ZH_CN/tree/f30ab7d8c58f85840a0afb548024b93642b518d5/eBook/examples/chapter_12/gob2.go) 编码到文件：

```go
// gob2.go
package main

import (
    "encoding/gob"
    "log"
    "os"
)

type Address struct {
    Type             string
    City             string
    Country          string
}

type VCard struct {
    FirstName    string
    LastName    string
    Addresses    []*Address
    Remark        string
}

var content    string

func main() {
    pa := &Address{"private", "Aartselaar","Belgium"}
    wa := &Address{"work", "Boom", "Belgium"}
    vc := VCard{"Jan", "Kersschot", []*Address{pa,wa}, "none"}
    // fmt.Printf("%v: \n", vc) // {Jan Kersschot [0x126d2b80 0x126d2be0] none}:
    // using an encoder:
    file, _ := os.OpenFile("vcard.gob", os.O_CREATE|os.O_WRONLY, 0666)
    defer file.Close()
    enc := gob.NewEncoder(file)
    err := enc.Encode(vc)
    if err != nil {
        log.Println("Error in encoding gob")
    }
}
```

**练习 12.8**：[degob.go](https://github.com/yangchuansheng/the-way-to-go_ZH_CN/tree/f30ab7d8c58f85840a0afb548024b93642b518d5/eBook/exercises/chapter_12/degob.go)：

写一个程序读取 vcard.gob 文件，解码并打印它的内容。

## 链接

* [目录](https://github.com/yangchuansheng/the-way-to-go_ZH_CN/tree/f30ab7d8c58f85840a0afb548024b93642b518d5/eBook/directory.md)
* 上一节：[XML 数据格式](/the-way-to-go-zh-cn/di-san-bu-fen-go-gao-ji-bian-cheng/12.0/12.10.md)
* 下一节：[Go 中的密码学](/the-way-to-go-zh-cn/di-san-bu-fen-go-gao-ji-bian-cheng/12.0/12.12.md)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ryanyang.gitbook.io/the-way-to-go-zh-cn/di-san-bu-fen-go-gao-ji-bian-cheng/12.0/12.11.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
