dragon2025 2015-02-23 00:50
浏览 22
已采纳

有没有一种方法可以使用编码/目标序列化循环数据结构?

I'm working on porting a neural network library to Go. I want to be able to save and restore a trained network, so I'm attempting to serialize it directly. The problem is, the network struct contains cycles in its field (Neuron A has a connection to Neuron B, which has a connection to Neuron A). Whenever I try to serialize the entire network with encoding/gob, it fails with a stackoverflow.

Here's a very simple example of code that breaks in the same way:

package main

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

type P struct {
    Name    string
    Q *Q
}

type Q struct {
    Name string
    P *P
}

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.

    p := &P{ "P", nil }
    q := &Q{ "Q", p }
    p.Q = q

    err := enc.Encode(p)
    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("%#v", p2)
}

http://play.golang.org/p/LrO0VlLnX4

Barring rewriting the entire structure of the library to avoid cycles, is there a straightforward way to get around this problem?

Thanks

  • 写回答

1条回答 默认 最新

  • doushi4956 2015-02-23 01:56
    关注

    You can't use gob directly, but fear not brave citizen of the world!

    You can implement the BinaryMarshaler/BinaryUnmarshaler interfaces on your type as a work around and gob will happily use them instead when it's encoding/decoding your type.

    func (p *P) MarshalBinary() (_ []byte, err error) {
        var buf bytes.Buffer
        enc := gob.NewEncoder(&buf)
        enc.Encode(p.Name)
        if p.Q == nil {
            return buf.Bytes(), nil
        }
        isCyclic := p.Q != nil && p.Q.P == p
        enc.Encode(isCyclic)
        if isCyclic {
            p.Q.P = nil
            err = enc.Encode(p.Q)
            p.Q.P = p
        } else {
            err = enc.Encode(p.Q)
        }
        //buf.Encode
        return buf.Bytes(), err
    }
    
    func (p *P) UnmarshalBinary(data []byte) (err error) {
        dec := gob.NewDecoder(bytes.NewReader(data))
        if err = dec.Decode(&p.Name); err != nil {
            return
        }
        var isCyclic bool
        if err = dec.Decode(&isCyclic); err != nil {
            return
        }
        err = dec.Decode(&p.Q)
        if isCyclic {
            p.Q.P = p
        }
        return
    }
    

    <kbd>playground</kbd>

    warning creating a new decoder/encoder every time is extremely inefficient, you might want to look into using binary.*.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 有了解d3和topogram.js库的吗?有偿请教
  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 unity第一人称射击小游戏,有demo,在原脚本的基础上进行修改以达到要求
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看
  • ¥15 关于#Java#的问题,如何解决?
  • ¥15 加热介质是液体,换热器壳侧导热系数和总的导热系数怎么算
  • ¥100 嵌入式系统基于PIC16F882和热敏电阻的数字温度计
  • ¥15 cmd cl 0x000007b
  • ¥20 BAPI_PR_CHANGE how to add account assignment information for service line