MarshalBinary time.Time:预测其字节大小

问题描述 投票:0回答:1

TL; DR;

可以预测大小为time.Time.MarshalBinary()的返回的缓冲区,以在其他自定义类型的二进制解组期间提供帮助。


尝试为我的类型写一个compact BinaryMarshaler(即避免存储不必要的大小标记):

type Item struct {
    t time.Time
    m *pb.Device // implements proto.Message - so use proto.Marshal(...) to Marshal
}

两个字段都具有BinaryMarshaler,所以这应该很容易。第一步是将两个封送的[]bytes附加在一起(时间第一,原型消息第二)。但是如何Unmarshal,因为time.Time.UnmarshalBinary并不指示消耗了多少字节,因此应该使用哪个偏移量来开始proto.Message编组?

检查time source建议time.Time.MarshalBinary()始终返回15个字节(第一个字节保存1的算法版本)。从go版本1.2.2到今天(1.14),这似乎都是正确的。

因此,可以计算出time.UnmarshalBinary消耗的字节数以帮助自定义BinaryUnmarshalers-并避免使用诸如以下的硬编码假设:

func (i *Item) UnmarshalBinary(b []byte) error {
    const (
        timeV     = 1
        timeV1Len = 15
    )
    if len(b) == 0 {
        *i = Item{} // no data - set to zero value
        return nil
    }
    if b[0] != timeV {
        return fmt.Errorf("time.Time binary marshaled at unsupported version %d (expected version %d)", b[0], timeV)
    }
    if len(b) < timeV1Len {
        return fmt.Errorf("data too short: should be >= %d bytes, got %d byte(s)", timeV1Len, len(b))
    }
    if err = i.t.UnmarshalBinary(b[:timeV1Len]); err != nil {
        return err
    }
    if len(b[timeV1Len:]) == 0 {
        i.m = nil // no more data, so set Message nil
        return nil
    }
    i.m = &pb.Device{}
    return proto.Unmarshal(b[timeV1Len:], i.m)
}
go marshalling
1个回答
2
投票

据我所知,MarshalBinary的输出大小不受Go 1 Compatibility Promise的限制:

未指定的行为。 Go规范试图明确说明该语言的大多数属性,但是有些方面尚未定义。依赖此类未指定行为的程序可能会在将来的版本中中断。

Time.MarshalBinary没有指定其输出的大小,因此将被视为“未指定的行为”。

© www.soinside.com 2019 - 2024. All rights reserved.