• Go之gob包的使用


    gob包("encoding/gob")管理gob流——在encoder(编码器,也就是发送器)和decoder(解码器,也就是接受器)之间交换的字节流数据(gob 就是 go binary的缩写)。一般用于传递远端程序调用(RPC)的参数和结果。

    要使用gob,通过调用NewEncoder()方法先创建一个编码器,并向其提供一系列数据;然后在接收端,通过调用NewDecoder()方法创建一个解码器,它从数据流中恢复数据并将它们填写进本地变量里。下面会通过几个例子进行说明。

    发送端和接收端的值/类型不需要严格匹配。对结构体来说,某一字段(通过字段名进行识别)如果发送端有而接收端没有,会被忽略;接收端有而发送端没有的字段也会被忽略;发送端和接收端都有的字段其类型必须是可兼容的;发送端和接收端都会在gob流和实际go类型之间进行必要的指针取址/寻址工作。举例如下:

    下面是发送端的承载数据的结构体:
    struct { A, B int }
    可以和如下类型互相发送和接收:
    struct { A, B int } // 同一类型 *struct { A, B int } // 结构体需要额外重定向(指针) struct { *A, **B int } // 字段需要额外重定向(指针) struct { A, B int64 } // 同为整型/浮点型且符号类型相同的不同值类型

    可以发送给如下任一类型: struct { A, B int } // 同一类型 struct { B, A int } // 字段顺序改变无影响,按名称匹配 struct { A, B, C int } // 忽略多出的字段C struct { B int } // 忽略缺少的字段A,会丢弃A的值 struct { B, C int } // 忽略缺少的字段A,忽略多出的字段C

    但尝试发送给如下类型的话就会导致错误: struct { A int; B uint } // B字段改变了符号类型 struct { A int; B float } // B字段改变了类型 struct { } // 无共同字段名 struct { C, D int } // 无共同字段名

    首先来看一个关于encode/decode结构体数据类型的示例。仔细观察这个例子,有助理解上面所说的发送端和接收端之间字段匹配的问题。

    type P struct {
        X, Y, Z int
        Name    string
    }
    
    type Q struct {
        X, Y *int32
        Name string
    }
    
    type R struct {
        Y, W int
    }
    
    // This example shows the basic usage of the package: Create an encoder,
    // transmit some values, receive them with a decoder.
    func GobBasic() {
        // 初始化 encoder 和 decoder
        var buf bytes.Buffer
        encoder := gob.NewEncoder(&buf) // will write to buf
        decoder := gob.NewDecoder(&buf) // will read from buf
    
        // Encode (send) some values
        err := encoder.Encode(P{X: 3, Y: 4, Z: 5, Name: "hello"})
        if err != nil {
            log.Fatal("Encode error:",err)
        }
      
    // case 1
    // Decode (receive) and print the values
    //var q Q //err = decoder.Decode(&q) //if err != nil { // log.Fatal("Decode error:",err) //} // //// 注意,不能写成 q.X,因为在接收方,定义的是 int型 指针 //// *(q.X) 与 *q.Y 结果相同,但前者语义更加明确 //fmt.Printf("%d %d %s ", *(q.X), *q.Y, q.Name) //case 2
    //var p P //err = decoder.Decode(&p) //if err != nil { // log.Fatal("Decode error:",err) //} //// 这里的接收方和传入方格式完全一致 //fmt.Printf("%d %d %d %s ", p.X, p.Y, p.Z, p.Name)
       // case 3 var r R err = decoder.Decode(&r) if err != nil { log.Fatal("Decode error:",err) } //fmt.Printf("%d %d %d %s ", r.X, r.Y, r.Z, r.Name) // 会输出如下:因为接收端是根据字段名称进行匹配的 // r.X undefined (type R has no field or method X) // r.Z undefined (type R has no field or method Z) // r.Name undefined (type R has no field or method Name) fmt.Printf("%d ", r.Y) // ok }

    接着我们看一下encode/decode 接口类型的值是如何操作的。与其他常规的类型(比如结构体)最大的不同在于:需要注册一个明确的实现该接口的类型。

    示例如下:

    type Point struct {
        X, Y int
    }
    func (p Point) Hypotenuse() float64 {
        // Hypot returns Sqrt(p*p + q*q)
        return math.Hypot(float64(p.X), float64(p.Y))
    }
    type Pythagoras interface {
        Hypotenuse() float64
    }
    
    // 这个例子展示了如何 encode/decode 一个接口类型(interface{})的值
    // 与其他常规的类型(比如结构体)最大的不同在于:
    // 需要注册一个明确的实现该接口的类型
    func GobInterface()  {
        // 我们必须要对encoder和decoder注册具体的类型,
        // 因为通常来说,decoder和encoder是在不同的机器上的。
        // 经过“注册”,解析引擎才能知道实现这一接口的具体类型是什么
        // (因为同一个接口可以有多种不同的实现)
        gob.Register(Point{})
    
        p1 := Point{X: 3, Y: 4}
        fmt.Println(p1.Hypotenuse()) // 5
        // 编码,再解码,观察解码后返回的结果是否一致
        b, _ := encode(p1)
        p2, _ := decode(b)
        fmt.Println(p2.Hypotenuse()) // 5
    }
    
    // 编码,把结构体数据编码成字节流数据
    func encode(p Pythagoras) ([]byte, error) {
        var buf bytes.Buffer
        encoder := gob.NewEncoder(&buf) // 构造编码器,并把数据写进buf中
        if err := encoder.Encode(&p); err != nil {
            log.Printf("encode error: %v
    ", err)
            return nil, err
        }
        return buf.Bytes(), nil
    }
    
    // 解码,把字节流数据解析成结构体数据
    func decode(b []byte) (Pythagoras, error) {
        //var buf bytes.Buffer
        bufPtr := bytes.NewBuffer(b)      // 返回的类型是 *Buffer,而不是 Buffer。注意一下
        decoder := gob.NewDecoder(bufPtr) // 从 bufPtr 中获取数据
        var p Pythagoras
        if err := decoder.Decode(&p); err != nil { // 将数据写进变量 p 中
            return Point{}, err
        }
        return p, nil
    }
  • 相关阅读:
    Mysql 时间字段(加上或者减去一段时间)
    awk数组与语法
    awk模块、变量、执行
    awk简介与表达式实例
    图数据库
    推荐几款优秀的开源博客系统
    红黑树
    用户画像基础概念
    Panda Global获悉,美国承诺4年内明确区块链数字资产监管方式!
    重庆聚焦区块链应用,Panda Global觉得春天真的来了!
  • 原文地址:https://www.cnblogs.com/kkbill/p/11725966.html
Copyright © 2020-2023  润新知