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)
}
据我所知,MarshalBinary
的输出大小不受Go 1 Compatibility Promise的限制:
未指定的行为。 Go规范试图明确说明该语言的大多数属性,但是有些方面尚未定义。依赖此类未指定行为的程序可能会在将来的版本中中断。
Time.MarshalBinary没有指定其输出的大小,因此将被视为“未指定的行为”。