MarshalBinary time.Time:预测其字节大小
MarshalBinary time.Time: predicting its byte-size
TL;DR;
Can one predict the buffer returned by size time.Time.MarshalBinary() - to assist during binary unmarshaling of other custom types.
尝试为我的类型写一个 compact BinaryMarshaler(即避免存储不必要的大小标记):
type Item struct {
t time.Time
m *pb.Device // implements proto.Message - so use proto.Marshal(...) to Marshal
}
这两个字段都有 BinaryMarshaler,所以这应该很容易。第一步,是将两个编组的 []bytes
附加在一起(时间第一,proto.Message 第二)。但是如何 Unmarshal
,因为 time.Time.UnmarshalBinary 并不表示消耗了多少字节 - 那么应该使用什么偏移量来开始 proto.Message
解组?
检查 time source 表明 time.Time.MarshalBinary()
将始终 return 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:
Unspecified behavior. The Go specification tries to be explicit about most properties of the language, but there are some aspects that are undefined. Programs that depend on such unspecified behavior may break in future releases.
Time.MarshalBinary 未指定其输出的大小,因此它会被视为 "unspecified behavior".
TL;DR;
Can one predict the buffer returned by size time.Time.MarshalBinary() - to assist during binary unmarshaling of other custom types.
尝试为我的类型写一个 compact BinaryMarshaler(即避免存储不必要的大小标记):
type Item struct {
t time.Time
m *pb.Device // implements proto.Message - so use proto.Marshal(...) to Marshal
}
这两个字段都有 BinaryMarshaler,所以这应该很容易。第一步,是将两个编组的 []bytes
附加在一起(时间第一,proto.Message 第二)。但是如何 Unmarshal
,因为 time.Time.UnmarshalBinary 并不表示消耗了多少字节 - 那么应该使用什么偏移量来开始 proto.Message
解组?
检查 time source 表明 time.Time.MarshalBinary()
将始终 return 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:
Unspecified behavior. The Go specification tries to be explicit about most properties of the language, but there are some aspects that are undefined. Programs that depend on such unspecified behavior may break in future releases.
Time.MarshalBinary 未指定其输出的大小,因此它会被视为 "unspecified behavior".