zoukankan      html  css  js  c++  java
  • 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
    }
  • 相关阅读:
    陶瓷电容的结构、工艺、失效模式
    Vue.js最佳实践
    Vue 超快速学习
    CSS 小技巧
    HTML5 Canvas
    webkit下面的CSS设置滚动条
    Some untracked working tree files would be overwritten by checkout. Please move or remove them before you can checkout. View them
    JSCS: Please specify path to 'JSCS' package
    React中ref的使用方法
    React 60S倒计时
  • 原文地址:https://www.cnblogs.com/kkbill/p/11725966.html
Copyright © 2011-2022 走看看