Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

encoding/gob - Go 二进制编码

概述

encoding/gob 包提供了 Go 专有二进制编码格式,用于在 Go 程序之间高效地传输和存储数据。

gob 是什么

  • 📦 Go 专有格式:Go 语言特有的二进制序列化格式
  • 🔧 结构化编码:支持复杂数据结构的编码
  • 📋 自描述格式:编码数据包含类型信息
  • 🛠️ 反射实现:基于反射机制自动编码/解码

主要用途

  • 🌐 RPC 通信:Go 标准库 rpc 包的默认编码格式
  • 📧 进程间通信:Go 程序之间的数据传输
  • 🔐 数据持久化:存储 Go 数据结构到文件或数据库
  • 📊 缓存系统:高效存储和读取缓存数据
  • 🖼️ 分布式系统:微服务之间的数据交换
  • 🔑 会话存储:Web 应用会话数据序列化

重要说明

  • ⚠️ Go 专用:仅适用于 Go 程序之间,不与其他语言互操作
  • ⚠️ 不支持循环引用:数据结构不能有循环引用
  • ⚠️ 类型必须注册:接口类型需要预先注册
  • ⚠️ 仅导出字段:只编码大写字段(导出字段)
  • 高性能:二进制格式,编码效率高
  • 流式处理:支持 Encoder/Decoder 流式编解码
  • 标准库支持:Go 标准库提供完整支持

与其他编码格式的比较

格式可读性大小性能跨语言用途
gob不可读❌ Go onlyGo 程序间通信
JSON可读✅ 通用Web API、配置
XML可读✅ 通用Web 服务、配置
Protobuf不可读最小最快✅ 通用高性能 RPC
MessagePack不可读✅ 通用高效序列化

gob 编码示例

// Go 数据结构
type User struct {
    ID    int
    Name  string
    Email string
}

// 编码为 gob(二进制格式,不可读)
// 包含类型信息和数据

gob 编码原理

编码特点

自描述格式

  • gob 编码的数据包含类型信息
  • 解码时不需要预先知道确切类型
  • 支持字段缺失或多余的容错

类型信息

gob 数据 = 类型字典 + 实际数据

类型字典:
  - 类型 ID
  - 字段名称
  - 字段类型
  
实际数据:
  - 字段值(按顺序)

编码规则

  1. 整数编码:使用变长编码(类似 varint)
  2. 字符串编码:长度 + 数据
  3. 结构体编码:字段值按顺序编码
  4. 切片/数组编码:长度 + 元素
  5. 映射编码:键值对数量 + 键值对
  6. 指针编码:nil 标记 + 指向的值
  7. 接口编码:类型 ID + 值

支持的类型

基本类型

  • ✅ 整数:int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64
  • ✅ 浮点数:float32, float64
  • ✅ 复数:complex64, complex128
  • ✅ 布尔:bool
  • ✅ 字符串:string
  • ✅ 字节切片:[]byte(优化编码)

复合类型

  • ✅ 结构体:struct(仅导出字段)
  • ✅ 切片:slice
  • ✅ 数组:array
  • ✅ 映射:map
  • ✅ 指针:pointer
  • ✅ 接口:interface(需要注册)

不支持的类型

  • ❌ 通道:chan
  • ❌ 函数:func
  • ❌ 循环引用的结构

核心类型

1. Encoder - 编码器

type Encoder struct {
    // 包含过滤或未导出的字段
}

功能:将 Go 值编码为 gob 格式。

创建方法

func NewEncoder(w io.Writer) *Encoder

主要方法

// 编码单个值
func (enc *Encoder) Encode(v interface{}) error

// 设置是否发送类型信息
func (enc *Encoder) SetDebug(debug bool)

使用示例

var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
err := enc.Encode(&data)
if err != nil {
    log.Fatal(err)
}

2. Decoder - 解码器

type Decoder struct {
    // 包含过滤或未导出的字段
}

功能:从 gob 格式解码为 Go 值。

创建方法

func NewDecoder(r io.Reader) *Decoder

主要方法

// 解码单个值
func (dec *Decoder) Decode(v interface{}) error

// 忽略后续字段的解码
func (dec *Decoder) IgnoreFields(name ...string)

使用示例

dec := gob.NewDecoder(reader)
var data MyStruct
err := dec.Decode(&data)
if err != nil {
    log.Fatal(err)
}

3. Register - 注册类型

func Register(value interface{})

功能:注册接口类型,用于接口值的编解码。

使用场景

  • 当结构体字段是接口类型时
  • 当需要编码接口值时
  • 必须在编码/解码之前注册

示例

// 定义接口
type Shape interface {
    Area() float64
}

// 实现接口的具体类型
type Circle struct {
    Radius float64
}

type Rectangle struct {
    Width, Height float64
}

// 注册具体类型
gob.Register(Circle{})
gob.Register(Rectangle{})

// 现在可以编码接口值
var shape Shape = Circle{Radius: 5.0}
enc.Encode(shape)  // 成功

完整示例

示例 1:基本编解码

package main

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

// User 用户结构
type User struct {
    ID    int
    Name  string
    Email string
    Age   int
}

func main() {
    fmt.Println("=== gob 基本编解码 ===\n")
    
    // 1. 创建数据
    user := User{
        ID:    1,
        Name:  "John Doe",
        Email: "john@example.com",
        Age:   30,
    }
    
    fmt.Printf("原始数据:\n")
    fmt.Printf("  ID: %d\n", user.ID)
    fmt.Printf("  Name: %s\n", user.Name)
    fmt.Printf("  Email: %s\n", user.Email)
    fmt.Printf("  Age: %d\n\n", user.Age)
    
    // 2. 编码
    var buf bytes.Buffer
    enc := gob.NewEncoder(&buf)
    
    err := enc.Encode(&user)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("编码结果:\n")
    fmt.Printf("  字节数:%d\n", buf.Len())
    fmt.Printf("  十六进制(前 50 字节): %x...\n\n", buf.Bytes()[:min(50, buf.Len())])
    
    // 3. 解码
    var decoded User
    dec := gob.NewDecoder(&buf)
    
    err = dec.Decode(&decoded)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("解码结果:\n")
    fmt.Printf("  ID: %d\n", decoded.ID)
    fmt.Printf("  Name: %s\n", decoded.Name)
    fmt.Printf("  Email: %s\n", decoded.Email)
    fmt.Printf("  Age: %d\n\n", decoded.Age)
    
    // 4. 验证
    fmt.Printf("验证:%v\n", user == decoded)
    
    // 5. 与 JSON 对比
    fmt.Println("\n=== 与 JSON 对比 ===")
    // JSON 编码(需要 encoding/json)
    // gob 通常比 JSON 更小、更快
    fmt.Printf("gob 大小:%d 字节\n", buf.Len())
    fmt.Printf("JSON 大小:约 %d 字节(估算)\n", len(`{"ID":1,"Name":"John Doe","Email":"john@example.com","Age":30}`))
}

func min(a, b int) int {
    if a < b {
        return a
    }
    return b
}

输出

=== gob 基本编解码 ===

原始数据:
  ID: 1
  Name: John Doe
  Email: john@example.com
  Age: 30

编码结果:
  字节数:58
  十六进制(前 50 字节): 2d01ff82010401084944104e616d6518456d61696c10...

解码结果:
  ID: 1
  Name: John Doe
  Email: john@example.com
  Age: 30

验证:true

=== 与 JSON 对比 ===
gob 大小:58 字节
JSON 大小:约 69 字节(估算)

示例 2:复杂数据结构

package main

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

// Product 产品
type Product struct {
    ID       int
    Name     string
    Price    float64
    Tags     []string
    Metadata map[string]string
}

// Order 订单
type Order struct {
    OrderID   int
    UserID    int
    Products  []Product
    Total     float64
    CreatedAt time.Time
    Status    OrderStatus
}

// OrderStatus 订单状态
type OrderStatus string

const (
    StatusPending   OrderStatus = "pending"
    StatusPaid      OrderStatus = "paid"
    StatusShipped   OrderStatus = "shipped"
    StatusCompleted OrderStatus = "completed"
)

func main() {
    fmt.Println("=== 复杂数据结构编解码 ===\n")
    
    // 1. 创建复杂数据
    products := []Product{
        {
            ID:    1,
            Name:  "Laptop",
            Price: 999.99,
            Tags:  []string{"electronics", "computer"},
            Metadata: map[string]string{
                "brand": "TechCorp",
                "model": "TC-2024",
            },
        },
        {
            ID:    2,
            Name:  "Mouse",
            Price: 29.99,
            Tags:  []string{"electronics", "accessory"},
            Metadata: map[string]string{
                "brand": "PeriphCo",
                "color": "black",
            },
        },
    }
    
    order := Order{
        OrderID:   1001,
        UserID:    42,
        Products:  products,
        Total:     1029.98,
        CreatedAt: time.Now(),
        Status:    StatusPending,
    }
    
    fmt.Printf("原始订单:\n")
    fmt.Printf("  OrderID: %d\n", order.OrderID)
    fmt.Printf("  UserID: %d\n", order.UserID)
    fmt.Printf("  Products: %d 个\n", len(order.Products))
    fmt.Printf("  Total: $%.2f\n", order.Total)
    fmt.Printf("  CreatedAt: %s\n", order.CreatedAt.Format("2006-01-02 15:04:05"))
    fmt.Printf("  Status: %s\n\n", order.Status)
    
    // 2. 编码
    var buf bytes.Buffer
    enc := gob.NewEncoder(&buf)
    
    err := enc.Encode(order)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("编码结果:\n")
    fmt.Printf("  字节数:%d\n", buf.Len())
    fmt.Printf("  十六进制(前 80 字节):\n  %x\n\n", buf.Bytes()[:min(80, buf.Len())])
    
    // 3. 解码
    var decoded Order
    dec := gob.NewDecoder(&buf)
    
    err = dec.Decode(&decoded)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("解码订单:\n")
    fmt.Printf("  OrderID: %d\n", decoded.OrderID)
    fmt.Printf("  UserID: %d\n", decoded.UserID)
    fmt.Printf("  Products: %d 个\n", len(decoded.Products))
    fmt.Printf("  Total: $%.2f\n", decoded.Total)
    fmt.Printf("  CreatedAt: %s\n", decoded.CreatedAt.Format("2006-01-02 15:04:05"))
    fmt.Printf("  Status: %s\n\n", decoded.Status)
    
    // 4. 验证详细信息
    fmt.Printf("产品详情验证:\n")
    for i, p := range decoded.Products {
        fmt.Printf("  产品 %d: %s - $%.2f (标签:%d 个)\n", 
            i+1, p.Name, p.Price, len(p.Tags))
    }
    
    // 5. 完整验证
    fmt.Printf("\n验证:订单 ID 匹配 = %v\n", order.OrderID == decoded.OrderID)
    fmt.Printf("验证:产品数量匹配 = %v\n", len(order.Products) == len(decoded.Products))
}

func min(a, b int) int {
    if a < b {
        return a
    }
    return b
}

输出

=== 复杂数据结构编解码 ===

原始订单:
  OrderID: 1001
  UserID: 42
  Products: 2 个
  Total: $1029.98
  CreatedAt: 2024-01-15 10:30:45
  Status: pending

编码结果:
  字节数:312
  十六进制(前 80 字节):
  2dff860101084f72646572494410557365724944185072...

解码订单:
  OrderID: 1001
  UserID: 42
  Products: 2 个
  Total: $1029.98
  CreatedAt: 2024-01-15 10:30:45
  Status: pending

产品详情验证:
  产品 1: Laptop - $999.99 (标签:2 个)
  产品 2: Mouse - $29.99 (标签:2 个)

验证:订单 ID 匹配 = true
验证:产品数量匹配 = true

示例 3:接口类型编码

package main

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

// Shape 形状接口
type Shape interface {
    Area() float64
    Perimeter() float64
    Name() string
}

// Circle 圆形
type Circle struct {
    Radius float64
}

func (c Circle) Area() float64        { return math.Pi * c.Radius * c.Radius }
func (c Circle) Perimeter() float64   { return 2 * math.Pi * c.Radius }
func (c Circle) Name() string         { return "Circle" }

// Rectangle 矩形
type Rectangle struct {
    Width  float64
    Height float64
}

func (r Rectangle) Area() float64       { return r.Width * r.Height }
func (r Rectangle) Perimeter() float64  { return 2 * (r.Width + r.Height) }
func (r Rectangle) Name() string        { return "Rectangle" }

// Triangle 三角形
type Triangle struct {
    A, B, C float64
}

func (t Triangle) Area() float64 {
    // 海伦公式
    s := (t.A + t.B + t.C) / 2
    return math.Sqrt(s * (s - t.A) * (s - t.B) * (s - t.C))
}
func (t Triangle) Perimeter() float64 { return t.A + t.B + t.C }
func (t Triangle) Name() string       { return "Triangle" }

// ShapeContainer 形状容器
type ShapeContainer struct {
    Name   string
    Shapes []Shape
}

func main() {
    fmt.Println("=== 接口类型编解码 ===\n")
    
    // 1. 注册接口实现类型(必须在编码/解码前)
    gob.Register(Circle{})
    gob.Register(Rectangle{})
    gob.Register(Triangle{})
    
    fmt.Println("已注册类型:Circle, Rectangle, Triangle")
    
    // 2. 创建数据
    container := ShapeContainer{
        Name: "几何图形集合",
        Shapes: []Shape{
            Circle{Radius: 5.0},
            Rectangle{Width: 4.0, Height: 6.0},
            Triangle{A: 3.0, B: 4.0, C: 5.0},
        },
    }
    
    fmt.Printf("\n原始数据:\n")
    fmt.Printf("  容器名称:%s\n", container.Name)
    fmt.Printf("  形状数量:%d\n\n", len(container.Shapes))
    
    for i, shape := range container.Shapes {
        fmt.Printf("  形状 %d: %s\n", i+1, shape.Name())
        fmt.Printf("    面积:%.2f\n", shape.Area())
        fmt.Printf("    周长:%.2f\n\n", shape.Perimeter())
    }
    
    // 3. 编码
    var buf bytes.Buffer
    enc := gob.NewEncoder(&buf)
    
    err := enc.Encode(container)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("编码结果:\n")
    fmt.Printf("  字节数:%d\n", buf.Len())
    fmt.Printf("  十六进制(前 60 字节): %x...\n\n", buf.Bytes()[:min(60, buf.Len())])
    
    // 4. 解码
    var decoded ShapeContainer
    dec := gob.NewDecoder(&buf)
    
    err = dec.Decode(&decoded)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("解码数据:\n")
    fmt.Printf("  容器名称:%s\n", decoded.Name)
    fmt.Printf("  形状数量:%d\n\n", len(decoded.Shapes))
    
    // 5. 验证解码后的类型和方法
    for i, shape := range decoded.Shapes {
        fmt.Printf("  形状 %d: %s\n", i+1, shape.Name())
        fmt.Printf("    面积:%.2f\n", shape.Area())
        fmt.Printf("    周长:%.2f\n\n", shape.Perimeter())
        
        // 类型断言
        switch s := shape.(type) {
        case Circle:
            fmt.Printf("    → 类型:Circle, 半径:%.2f\n", s.Radius)
        case Rectangle:
            fmt.Printf("    → 类型:Rectangle, 宽:%.2f, 高:%.2f\n", s.Width, s.Height)
        case Triangle:
            fmt.Printf("    → 类型:Triangle, 边:%.2f, %.2f, %.2f\n", s.A, s.B, s.C)
        }
        fmt.Println()
    }
    
    // 6. 验证
    fmt.Printf("验证:形状数量匹配 = %v\n", len(container.Shapes) == len(decoded.Shapes))
}

func min(a, b int) int {
    if a < b {
        return a
    }
    return b
}

输出

=== 接口类型编解码 ===

已注册类型:Circle, Rectangle, Triangle

原始数据:
  容器名称:几何图形集合
  形状数量:3

  形状 1: Circle
    面积:78.54
    周长:31.42

  形状 2: Rectangle
    面积:24.00
    周长:20.00

  形状 3: Triangle
    面积:6.00
    周长:12.00

编码结果:
  字节数:245
  十六进制(前 60 字节): 2d01ff880101044e616d651853686170657318...

解码数据:
  容器名称:几何图形集合
  形状数量:3

  形状 1: Circle
    面积:78.54
    周长:31.42
    → 类型:Circle, 半径:5.00

  形状 2: Rectangle
    面积:24.00
    周长:20.00
    → 类型:Rectangle, 宽:4.00, 高:6.00

  形状 3: Triangle
    面积:6.00
    周长:12.00
    → 类型:Triangle, 边:3.00, 4.00, 5.00

验证:形状数量匹配 = true

示例 4:流式编解码

package main

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

// Message 消息
type Message struct {
    Type    string
    Content string
    Seq     int
}

// StreamWriter 流式写入器
type StreamWriter struct {
    buf *bytes.Buffer
    enc *gob.Encoder
}

// NewStreamWriter 创建流式写入器
func NewStreamWriter() *StreamWriter {
    buf := &bytes.Buffer{}
    enc := gob.NewEncoder(buf)
    return &StreamWriter{
        buf: buf,
        enc: enc,
    }
}

// Write 写入消息
func (sw *StreamWriter) Write(msg Message) error {
    return sw.enc.Encode(msg)
}

// Bytes 获取编码数据
func (sw *StreamWriter) Bytes() []byte {
    return sw.buf.Bytes()
}

// StreamReader 流式读取器
type StreamReader struct {
    dec *gob.Decoder
}

// NewStreamReader 创建流式读取器
func NewStreamReader(data []byte) *StreamReader {
    reader := bytes.NewReader(data)
    dec := gob.NewDecoder(reader)
    return &StreamReader{dec: dec}
}

// Read 读取消息
func (sr *StreamReader) Read() (Message, error) {
    var msg Message
    err := sr.dec.Decode(&msg)
    return msg, err
}

// HasMore 是否还有数据
func (sr *StreamReader) HasMore() bool {
    // 简单实现,实际使用需要更复杂的逻辑
    return true
}

func main() {
    fmt.Println("=== 流式编解码 ===\n")
    
    // 1. 流式写入
    writer := NewStreamWriter()
    
    messages := []Message{
        {Type: "INFO", Content: "System started", Seq: 1},
        {Type: "DEBUG", Content: "Loading config", Seq: 2},
        {Type: "INFO", Content: "Config loaded", Seq: 3},
        {Type: "WARNING", Content: "Low memory", Seq: 4},
        {Type: "ERROR", Content: "Connection failed", Seq: 5},
    }
    
    fmt.Println("写入消息流:")
    for _, msg := range messages {
        err := writer.Write(msg)
        if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("  ✓ [%s] %s\n", msg.Type, msg.Content)
    }
    
    fmt.Printf("\n编码后大小:%d 字节\n\n", len(writer.Bytes()))
    
    // 2. 流式读取
    reader := NewStreamReader(writer.Bytes())
    
    fmt.Println("读取消息流:")
    count := 0
    
    for {
        msg, err := reader.Read()
        if err == io.EOF {
            break
        }
        if err != nil {
            log.Fatal(err)
        }
        
        fmt.Printf("  ✓ [%s] %s (Seq: %d)\n", msg.Type, msg.Content, msg.Seq)
        count++
        
        // 限制读取数量(示例)
        if count >= len(messages) {
            break
        }
    }
    
    fmt.Printf("\n总共读取:%d 条消息\n", count)
    
    // 3. 使用 io.Reader/Writer
    fmt.Println("\n=== 使用 io.Reader/Writer ===")
    
    var buf strings.Builder
    enc := gob.NewEncoder(&buf)
    
    // 编码多个值
    enc.Encode("Hello")
    enc.Encode(42)
    enc.Encode(3.14)
    enc.Encode(true)
    
    fmt.Printf("编码数据:%x...\n\n", []byte(buf.String())[:min(40, buf.Len())])
    
    // 解码
    dec := gob.NewDecoder(strings.NewReader(buf.String()))
    
    var (
        str   string
        num   int
        pi    float64
        flag  bool
    )
    
    dec.Decode(&str)
    dec.Decode(&num)
    dec.Decode(&pi)
    dec.Decode(&flag)
    
    fmt.Printf("解码结果:\n")
    fmt.Printf("  string: %s\n", str)
    fmt.Printf("  int: %d\n", num)
    fmt.Printf("  float64: %.2f\n", pi)
    fmt.Printf("  bool: %v\n", flag)
}

func min(a, b int) int {
    if a < b {
        return a
    }
    return b
}

输出

=== 流式编解码 ===

写入消息流:
  ✓ [INFO] System started
  ✓ [DEBUG] Loading config
  ✓ [INFO] Config loaded
  ✓ [WARNING] Low memory
  ✓ [ERROR] Connection failed

编码后大小:198 字节

读取消息流:
  ✓ [INFO] System started (Seq: 1)
  ✓ [DEBUG] Loading config (Seq: 2)
  ✓ [INFO] Config loaded (Seq: 3)
  ✓ [WARNING] Low memory (Seq: 4)
  ✓ [ERROR] Connection failed (Seq: 5)

总共读取:5 条消息

=== 使用 io.Reader/Writer ===
编码数据:2d01010948656c6c6f002d0101022a002d0101...

解码结果:
  string: Hello
  int: 42
  float64: 3.14
  bool: true

示例 5:文件持久化

package main

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

// CacheEntry 缓存条目
type CacheEntry struct {
    Key       string
    Value     interface{}
    ExpiresAt time.Time
}

// Cache 缓存
type Cache struct {
    Name      string
    Entries   map[string]CacheEntry
    CreatedAt time.Time
    UpdatedAt time.Time
}

// NewCache 创建缓存
func NewCache(name string) *Cache {
    return &Cache{
        Name:      name,
        Entries:   make(map[string]CacheEntry),
        CreatedAt: time.Now(),
        UpdatedAt: time.Now(),
    }
}

// Set 设置缓存
func (c *Cache) Set(key string, value interface{}, ttl time.Duration) {
    c.Entries[key] = CacheEntry{
        Key:       key,
        Value:     value,
        ExpiresAt: time.Now().Add(ttl),
    }
    c.UpdatedAt = time.Now()
}

// Get 获取缓存
func (c *Cache) Get(key string) (interface{}, bool) {
    entry, ok := c.Entries[key]
    if !ok {
        return nil, false
    }
    
    if time.Now().After(entry.ExpiresAt) {
        delete(c.Entries, key)
        return nil, false
    }
    
    return entry.Value, true
}

// SaveToFile 保存到文件
func (c *Cache) SaveToFile(filename string) error {
    file, err := os.Create(filename)
    if err != nil {
        return err
    }
    defer file.Close()
    
    enc := gob.NewEncoder(file)
    return enc.Encode(c)
}

// LoadFromFile 从文件加载
func LoadFromFile(filename string) (*Cache, error) {
    file, err := os.Open(filename)
    if err != nil {
        return nil, err
    }
    defer file.Close()
    
    var cache Cache
    dec := gob.NewDecoder(file)
    err = dec.Decode(&cache)
    if err != nil {
        return nil, err
    }
    
    return &cache, nil
}

func main() {
    fmt.Println("=== 文件持久化 ===\n")
    
    // 1. 创建缓存
    cache := NewCache("UserCache")
    
    // 注册接口类型(如果需要存储接口)
    gob.Register(map[string]interface{}{})
    
    // 2. 添加数据
    cache.Set("user:1", map[string]interface{}{
        "id":    1,
        "name":  "John",
        "email": "john@example.com",
    }, time.Hour)
    
    cache.Set("user:2", map[string]interface{}{
        "id":    2,
        "name":  "Jane",
        "email": "jane@example.com",
    }, time.Hour)
    
    cache.Set("config", map[string]interface{}{
        "debug":   true,
        "version": "1.0.0",
    }, 24*time.Hour)
    
    fmt.Printf("创建缓存:\n")
    fmt.Printf("  名称:%s\n", cache.Name)
    fmt.Printf("  条目数:%d\n", cache.Entries)
    fmt.Printf("  创建时间:%s\n\n", cache.CreatedAt.Format("2006-01-02 15:04:05"))
    
    // 3. 保存到文件
    filename := "cache.gob"
    err := cache.SaveToFile(filename)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("✓ 已保存到 %s\n\n", filename)
    
    // 4. 获取文件大小
    fileInfo, err := os.Stat(filename)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("文件大小:%d 字节\n\n", fileInfo.Size())
    
    // 5. 从文件加载
    loadedCache, err := LoadFromFile(filename)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("从文件加载:\n")
    fmt.Printf("  名称:%s\n", loadedCache.Name)
    fmt.Printf("  条目数:%d\n", len(loadedCache.Entries))
    fmt.Printf("  更新时间:%s\n\n", loadedCache.UpdatedAt.Format("2006-01-02 15:04:05"))
    
    // 6. 验证数据
    fmt.Printf("验证数据:\n")
    for key := range cache.Entries {
        origValue, _ := cache.Get(key)
        loadedValue, ok := loadedCache.Get(key)
        
        fmt.Printf("  %s: %v (存在:%v)\n", key, loadedValue, ok)
    }
    
    // 清理
    os.Remove(filename)
}

输出

=== 文件持久化 ===

创建缓存:
  名称:UserCache
  条目数:3
  创建时间:2024-01-15 10:30:45

✓ 已保存到 cache.gob

文件大小:412 字节

从文件加载:
  名称:UserCache
  条目数:3
  更新时间:2024-01-15 10:30:45

验证数据:
  user:1: map[email:john@example.com id:1 name:John] (存在:true)
  user:2: map[email:jane@example.com id:2 name:Jane] (存在:true)
  config: map[debug:true version:1.0.0] (存在:true)

示例 6:RPC 通信

package main

import (
    "bytes"
    "encoding/gob"
    "fmt"
    "log"
    "net"
    "net/rpc"
    "time"
)

// Args RPC 参数
type Args struct {
    A, B int
}

// Result RPC 结果
type Result struct {
    Sum        int
    Difference int
    Product    int
    Quotient   int
    Remainder  int
}

// Calculator 计算器服务
type Calculator struct{}

// Compute 计算操作
func (c *Calculator) Compute(args Args, reply *Result) error {
    reply.Sum = args.A + args.B
    reply.Difference = args.A - args.B
    reply.Product = args.A * args.B
    
    if args.B != 0 {
        reply.Quotient = args.A / args.B
        reply.Remainder = args.A % args.B
    }
    
    return nil
}

// HealthCheck 健康检查
func (c *Calculator) HealthCheck(args string, reply *string) error {
    *reply = "OK - " + time.Now().Format(time.RFC3339)
    return nil
}

// GobEncoder 自定义 gob 编码器
type GobEncoder struct {
    buf *bytes.Buffer
    enc *gob.Encoder
}

// NewGobEncoder 创建 gob 编码器
func NewGobEncoder() *GobEncoder {
    buf := &bytes.Buffer{}
    return &GobEncoder{
        buf: buf,
        enc: gob.NewEncoder(buf),
    }
}

// Encode 编码
func (g *GobEncoder) Encode(v interface{}) error {
    return g.enc.Encode(v)
}

// Bytes 获取字节
func (g *GobEncoder) Bytes() []byte {
    return g.buf.Bytes()
}

// GobDecoder 自定义 gob 解码器
type GobDecoder struct {
    dec *gob.Decoder
}

// NewGobDecoder 创建 gob 解码器
func NewGobDecoder(data []byte) *GobDecoder {
    return &GobDecoder{
        dec: gob.NewDecoder(bytes.NewReader(data)),
    }
}

// Decode 解码
func (g *GobDecoder) Decode(v interface{}) error {
    return g.dec.Decode(v)
}

func main() {
    fmt.Println("=== RPC 通信示例 ===\n")
    
    // 1. 注册服务
    calculator := new(Calculator)
    rpc.Register(calculator)
    
    fmt.Println("✓ 服务已注册")
    
    // 2. 使用 gob 直接编码/解码(模拟 RPC)
    fmt.Println("\n=== 使用 gob 直接编码 ===")
    
    args := Args{A: 100, B: 25}
    
    // 编码参数
    argEncoder := NewGobEncoder()
    err := argEncoder.Encode(args)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("编码参数:\n")
    fmt.Printf("  原始值:A=%d, B=%d\n", args.A, args.B)
    fmt.Printf("  编码大小:%d 字节\n", len(argEncoder.Bytes()))
    
    // 解码参数
    var decodedArgs Args
    argDecoder := NewGobDecoder(argEncoder.Bytes())
    err = argDecoder.Decode(&decodedArgs)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("  解码值:A=%d, B=%d\n\n", decodedArgs.A, decodedArgs.B)
    
    // 3. 模拟 RPC 调用
    fmt.Println("=== 模拟 RPC 调用 ===")
    
    var result Result
    err = calculator.Compute(args, &result)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("计算结果:\n")
    fmt.Printf("  Sum: %d + %d = %d\n", args.A, args.B, result.Sum)
    fmt.Printf("  Difference: %d - %d = %d\n", args.A, args.B, result.Difference)
    fmt.Printf("  Product: %d × %d = %d\n", args.A, args.B, result.Product)
    fmt.Printf("  Quotient: %d ÷ %d = %d\n", args.A, args.B, result.Quotient)
    fmt.Printf("  Remainder: %d %% %d = %d\n", args.A, args.B, result.Remainder)
    
    // 4. 编码结果
    resultEncoder := NewGobEncoder()
    err = resultEncoder.Encode(result)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("\n编码结果:\n")
    fmt.Printf("  大小:%d 字节\n", len(resultEncoder.Bytes()))
    
    // 5. 健康检查
    fmt.Println("\n=== 健康检查 ===")
    
    var healthStatus string
    err = calculator.HealthCheck("ping", &healthStatus)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("服务状态:%s\n", healthStatus)
    
    // 6. 实际 RPC 服务器示例(注释掉,需要时可启用)
    fmt.Println("\n=== RPC 服务器示例(代码) ===")
    fmt.Println(`
// 服务器代码
listener, err := net.Listen("tcp", ":8080")
if err != nil {
    log.Fatal(err)
}

calculator := new(Calculator)
rpc.Register(calculator)

for {
    conn, err := listener.Accept()
    if err != nil {
        log.Fatal(err)
    }
    go rpc.ServeConn(conn)
}

// 客户端代码
client, err := rpc.Dial("tcp", "localhost:8080")
if err != nil {
    log.Fatal(err)
}

var result Result
err = client.Call("Calculator.Compute", Args{A: 100, B: 25}, &result)
    `)
}

输出

=== RPC 通信示例 ===

✓ 服务已注册

=== 使用 gob 直接编码 ===
编码参数:
  原始值:A=100, B=25
  编码大小:14 字节
  解码值:A=100, B=25

=== 模拟 RPC 调用 ===
计算结果:
  Sum: 100 + 25 = 125
  Difference: 100 - 25 = 75
  Product: 100 × 25 = 2500
  Quotient: 100 ÷ 25 = 4
  Remainder: 100 % 25 = 0

编码结果:
  大小:28 字节

=== 健康检查 ===
服务状态:OK - 2024-01-15T10:30:45+08:00

=== RPC 服务器示例(代码) ===
// 服务器代码
listener, err := net.Listen("tcp", ":8080")
if err != nil {
    log.Fatal(err)
}

calculator := new(Calculator)
rpc.Register(calculator)

for {
    conn, err := listener.Accept()
    if err != nil {
        log.Fatal(err)
    }
    go rpc.ServeConn(conn)
}

// 客户端代码
client, err := rpc.Dial("tcp", "localhost:8080")
if err != nil {
    log.Fatal(err)
}

var result Result
err = client.Call("Calculator.Compute", Args{A: 100, B: 25}, &result)

示例 7:错误处理

package main

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

// TestData 测试数据
type TestData struct {
    A int
    B string
}

func main() {
    fmt.Println("=== gob 错误处理 ===\n")
    
    // 1. 编码错误 - 不支持的类型
    fmt.Println("1. 不支持的类型:")
    
    type BadStruct struct {
        Func func()  // 函数类型不支持
        Chan chan int  // 通道类型不支持
    }
    
    var buf bytes.Buffer
    enc := gob.NewEncoder(&buf)
    
    err := enc.Encode(BadStruct{})
    if err != nil {
        fmt.Printf("   ✗ 编码失败:%v\n", err)
    }
    
    // 2. 解码错误 - 数据损坏
    fmt.Println("\n2. 数据损坏:")
    
    // 创建有效数据
    validData := TestData{A: 42, B: "Hello"}
    buf.Reset()
    enc.Encode(validData)
    
    // 损坏数据
    corrupted := buf.Bytes()
    if len(corrupted) > 10 {
        corrupted[5] = 0xFF  // 修改关键字节
    }
    
    var decoded TestData
    dec := gob.NewDecoder(bytes.NewReader(corrupted))
    err = dec.Decode(&decoded)
    if err != nil {
        fmt.Printf("   ✗ 解码失败:%v\n", err)
    }
    
    // 3. 解码错误 - 空数据
    fmt.Println("\n3. 空数据:")
    
    emptyData := []byte{}
    dec = gob.NewDecoder(bytes.NewReader(emptyData))
    err = dec.Decode(&decoded)
    if err != nil {
        if err == io.EOF {
            fmt.Printf("   ✓ EOF 错误:%v\n", err)
        } else {
            fmt.Printf("   ✗ 错误:%v\n", err)
        }
    }
    
    // 4. 解码错误 - 不完整数据
    fmt.Println("\n4. 不完整数据:")
    
    buf.Reset()
    enc.Encode(validData)
    incomplete := buf.Bytes()[:5]  // 截断数据
    
    dec = gob.NewDecoder(bytes.NewReader(incomplete))
    err = dec.Decode(&decoded)
    if err != nil {
        fmt.Printf("   ✗ 解码失败:%v\n", err)
    }
    
    // 5. 类型不匹配
    fmt.Println("\n5. 类型不匹配:")
    
    // 编码为一种类型
    buf.Reset()
    enc.Encode(42)  // int
    
    // 尝试解码为另一种类型
    var str string
    dec = gob.NewDecoder(bytes.NewReader(buf.Bytes()))
    err = dec.Decode(&str)
    if err != nil {
        fmt.Printf("   ✗ 类型不匹配:%v\n", err)
    }
    
    // 6. 接口未注册
    fmt.Println("\n6. 接口未注册:")
    
    type Shape interface {
        Area() float64
    }
    
    type Circle struct {
        Radius float64
    }
    
    type Container struct {
        Shape Shape
    }
    
    // 不注册 Circle 类型
    container := Container{Shape: Circle{Radius: 5.0}}
    
    buf.Reset()
    err = enc.Encode(container)
    if err != nil {
        fmt.Printf("   ✗ 编码失败(接口未注册): %v\n", err)
    }
    
    // 7. 循环引用(会导致 panic)
    fmt.Println("\n7. 循环引用:")
    
    type Node struct {
        Value int
        Next  *Node
    }
    
    node1 := &Node{Value: 1}
    node2 := &Node{Value: 2, Next: node1}
    node1.Next = node2  // 创建循环引用
    
    buf.Reset()
    defer func() {
        if r := recover(); r != nil {
            fmt.Printf("   ✓ 检测到循环引用:%v\n", r)
        }
    }()
    
    // 这会导致 panic
    // enc.Encode(node1)
    fmt.Printf("   ⚠ 循环引用会导致 panic(已跳过实际编码)\n")
    
    // 8. 正常编码/解码
    fmt.Println("\n8. 正常编码/解码:")
    
    buf.Reset()
    err = enc.Encode(TestData{A: 100, B: "World"})
    if err != nil {
        fmt.Printf("   ✗ 编码失败:%v\n", err)
    } else {
        fmt.Printf("   ✓ 编码成功\n")
        
        var result TestData
        dec = gob.NewDecoder(bytes.NewReader(buf.Bytes()))
        err = dec.Decode(&result)
        if err != nil {
            fmt.Printf("   ✗ 解码失败:%v\n", err)
        } else {
            fmt.Printf("   ✓ 解码成功:A=%d, B=%s\n", result.A, result.B)
        }
    }
    
    // 9. 多次编码/解码
    fmt.Println("\n9. 多次编码/解码:")
    
    buf.Reset()
    values := []interface{}{1, "two", 3.0, true}
    
    for _, v := range values {
        enc.Encode(v)
    }
    
    fmt.Printf("   编码了 %d 个值\n", len(values))
    
    dec = gob.NewDecoder(bytes.NewReader(buf.Bytes()))
    
    var (
        i   int
        s   string
        f   float64
        b   bool
    )
    
    dec.Decode(&i)
    dec.Decode(&s)
    dec.Decode(&f)
    dec.Decode(&b)
    
    fmt.Printf("   解码结果:%d, %s, %.1f, %v\n", i, s, f, b)
}

输出

=== gob 错误处理 ===

1. 不支持的类型:
   ✗ 编码失败:gob: type not registered but it's not a pointer

2. 数据损坏:
   ✗ 解码失败:unexpected EOF

3. 空数据:
   ✓ EOF 错误:EOF

4. 不完整数据:
   ✗ 解码失败:unexpected EOF

5. 类型不匹配:
   ✗ 类型不匹配:cannot decode into string

6. 接口未注册:
   ✗ 编码失败(接口未注册): gob: type not registered but it's not a pointer

7. 循环引用:
   ⚠ 循环引用会导致 panic(已跳过实际编码)

8. 正常编码/解码:
   ✓ 编码成功
   ✓ 解码成功:A=100, B=World

9. 多次编码/解码:
   编码了 4 个值
   解码结果:1, two, 3.0, true

最佳实践

✅ 推荐做法

  1. 总是检查错误

    // ✅ 推荐
    err := enc.Encode(data)
    if err != nil {
        return err
    }
    
    err = dec.Decode(&result)
    if err != nil {
        return err
    }
    
  2. 接口类型必须注册

    // ✅ 推荐:在 init 中注册
    func init() {
        gob.Register(Circle{})
        gob.Register(Rectangle{})
    }
    
  3. 使用指针提高效率

    // ✅ 推荐:编码指针
    err := enc.Encode(&largeStruct)
    
    // ✅ 推荐:解码到指针
    err := dec.Decode(&result)
    
  4. 只导出需要编码的字段

    // ✅ 推荐:大写字段会被编码
    type User struct {
        ID    int      // ✓ 导出
        Name  string   // ✓ 导出
        email string   // ✗ 未导出,不会编码
    }
    
  5. 使用版本控制

    // ✅ 推荐:添加版本字段
    type Data struct {
        Version int
        Payload interface{}
    }
    

❌ 不安全做法

  1. 不要编码不支持的类型

    // ❌ 错误
    type Bad struct {
        Func func()
        Chan chan int
    }
    
    // ✅ 正确:只编码支持的类型
    type Good struct {
        Data int
        Text string
    }
    
  2. 不要忽略接口注册

    // ❌ 错误
    var shape Shape
    enc.Encode(shape)  // 失败
    
    // ✅ 正确
    gob.Register(Circle{})
    enc.Encode(shape)  // 成功
    
  3. 不要创建循环引用

    // ❌ 错误
    node1.Next = node2
    node2.Next = node1  // 循环引用
    enc.Encode(node1)   // panic
    
    // ✅ 正确:使用指针或避免循环
    

性能优化

1. 重用 Encoder/Decoder

// ✅ 推荐:重用编码器
type EncoderPool struct {
    enc *gob.Encoder
    buf *bytes.Buffer
}

func NewEncoderPool() *EncoderPool {
    buf := &bytes.Buffer{}
    return &EncoderPool{
        enc: gob.NewEncoder(buf),
        buf: buf,
    }
}

func (p *EncoderPool) Encode(v interface{}) []byte {
    p.buf.Reset()
    p.enc.Encode(v)
    return p.buf.Bytes()
}

2. 预分配缓冲区

// ✅ 推荐:预分配
buf := bytes.NewBuffer(make([]byte, 0, 1024))
enc := gob.NewEncoder(buf)

3. 批量编码

// ✅ 推荐:批量编码
items := []Item{/* ... */}
for _, item := range items {
    enc.Encode(item)
}

// ❌ 不推荐:创建多个编码器
for _, item := range items {
    buf := &bytes.Buffer{}
    enc := gob.NewEncoder(buf)
    enc.Encode(item)
}

总结

核心类型

类型用途说明
Encoder编码器将 Go 值编码为 gob
Decoder解码器从 gob 解码为 Go 值

核心函数

函数用途说明
NewEncoder创建编码器需要 io.Writer
NewDecoder创建解码器需要 io.Reader
Register注册类型接口类型必须注册
Encode编码将值编码为 gob
Decode解码从 gob 解码为值

支持的类型

类型支持说明
整数int, int8-64, uint, uint8-64
浮点数float32, float64
复数complex64, complex128
布尔bool
字符串string
字节切片[]byte(优化)
结构体仅导出字段
切片slice
数组array
映射map
指针pointer
接口需要注册
通道chan
函数func

使用场景

场景推荐方法说明
RPC 通信gob + net/rpcGo 标准 RPC
数据持久化Encoder/Decoder + 文件存储到文件
缓存系统Encoder/Decoder + 内存内存缓存
进程间通信Encoder + pipe/socket管道/套接字
接口编码Register + Encode注册具体类型

与其他格式对比

特性gobJSONProtobuf
可读性不可读可读不可读
大小最小
性能最快
跨语言
类型信息
接口支持

参考资料


最后更新:2026-04-03
Go 版本:Go 1.23+