gob 的深度拷贝

项目中用了protobuf 做 RPC 协议,然后据说 gob 的encoder 和 decoder 比 protobuf 效率更高,于是写了一个用于 protobuf 结构体的深度拷贝库函数

func DeepCopy(dst, src interface{}) error {
    var buf bytes.Buffer
    if err := gob.NewEncoder(&buf).Encode(src); err != nil {
        return err
    }
    return gob.NewDecoder(bytes.NewBuffer(buf.Bytes())).Decode(dst)
}

然而实际使用的时候发现有点坑。
gob 为了提高效率,对于 0 值是不拷贝的,不仅仅是整型的零值,还包括指向零值的指针,也不会拷贝。

测试代码如下:

package main

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

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

func main() {
    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.

    z   := 0
    y   := 1
    err := enc.Encode(P{0, &y, &z, "指向 0 值的指针的字段被忽略了"})
    if err != nil {
        log.Fatal("encode error:", err)
    }
    // Decode (receive) the value.
    var p2 P
    err = dec.Decode(&p2)
    if err != nil {
        log.Fatal("decode error:", err)
    }
    fmt.Printf("%q: {x:%d, y:%p, z:%p}\n", p2.Name, p2.X, p2.Y,p2.Z)
}

以上代码可以到 https://play.golang.org/p/xEB1ENZdfDl 这里去运行。
可以看到即使结构体 P 的成员 Z 不为 nil , 仅仅是 Z 指向的值为 0 , 这个指针值也不会被拷贝。而指向值不为 0 的 Y 则可以成功拷贝。

当然,如果不是用 protobuf 做协议,这个用法没有问题,可以将 Z== nil 和 *Z = 0 等效
但是对于 protobuf 来说,指针为 nil 这个值是默认不会序列化的,对于不同端(比如 iOS 或 Android 或 C ),判断可能不一样。所以protobuf 的深拷贝建议还是用 proto.Clone()

gob 相关参考: https://blog.golang.org/gobs-of-data

猜你喜欢

转载自blog.csdn.net/u011228889/article/details/80738285