自定義編組/解組自定義數據佈局。有很多實現的可能性。幾個注意事項:
- Byte order,little/big endian?
- 數據包/流佈局?
一個例子實施big-endian
與流格式:
// Big-Endian
// Size : 4, 4, 1, n, 4, n
// Types : uint32, uint32, uint8, []int, uint32, []float64
// Data : #numbytes, #nInt, #intSize, p.a, #nFloat, p.b
的挑戰是如何表示int
,因爲它的體系結構相關。樣品實施將是:
func (p transProp) MarshalBinary() ([]byte, error) {
//Get sizeof int (in bits) from strconv package
szInt := strconv.IntSize/8
nInt := len(p.a)
nFloat := len(p.b)
nStream := 4 + 4 + 1 + nInt*szInt + 4 + nFloat*8
stream := make([]byte, nStream)
pos := 0
//total number of bytes
binary.BigEndian.PutUint32(stream, uint32(nStream))
pos += 4
//num of items in p.a
binary.BigEndian.PutUint32(stream[pos:], uint32(nInt))
pos += 4
//int size
stream[pos] = uint8(szInt)
pos++
//items in a
switch szInt {
case 1:
for _, v := range p.a {
stream[pos] = uint8(v)
pos++
}
case 2: //16-bit
for _, v := range p.a {
binary.BigEndian.PutUint16(stream[pos:], uint16(v))
pos += 2
}
case 4: //32-bit
for _, v := range p.a {
binary.BigEndian.PutUint32(stream[pos:], uint32(v))
pos += 4
}
case 8: //64-bit
for _, v := range p.a {
binary.BigEndian.PutUint64(stream[pos:], uint64(v))
pos += 8
}
}
//number of items in p.b
binary.BigEndian.PutUint32(stream[pos:], uint32(nFloat))
pos += 4
//items in b
s := stream[pos:pos] //slice len=0, capacity=nFloat
buf := bytes.NewBuffer(s)
if err := binary.Write(buf, binary.BigEndian, p.b); err != nil {
return nil, err
}
return stream, nil
}
func (p *transProp) UnmarshalBinary(data []byte) error {
buf := bytes.NewBuffer(data)
var intSize uint8
var k, nBytes, nInt, nFloat uint32
//num bytes
if err := binary.Read(buf, binary.BigEndian, &nBytes); err != nil {
return err
}
if len(data) < int(nBytes) {
return errors.New("len(data) < #Bytes")
}
//num of int items
if err := binary.Read(buf, binary.BigEndian, &nInt); err != nil {
return err
}
//int size
if err := binary.Read(buf, binary.BigEndian, &intSize); err != nil {
return err
}
//read int into p.a
pos := 0
stream := buf.Bytes()
p.a = make([]int, nInt)
switch intSize {
case 1:
for pos = 0; pos < int(nInt); pos++ {
p.a[pos] = int(stream[pos])
}
case 2:
for k = 0; k < nInt; k++ {
p.a[k] = int(binary.BigEndian.Uint16(stream[pos:]))
pos += 2
}
case 4:
for k = 0; k < nInt; k++ {
p.a[k] = int(binary.BigEndian.Uint32(stream[pos:]))
pos += 4
}
case 8:
for k = 0; k < nInt; k++ {
p.a[k] = int(binary.BigEndian.Uint64(stream[pos:]))
pos += 8
}
}
//advance buffer
buf.Next(pos)
//num of float64 items
if err := binary.Read(buf, binary.BigEndian, &nFloat); err != nil {
return err
}
//items in b
p.b = make([]float64, nFloat)
if err := binary.Read(buf, binary.BigEndian, p.b); err != nil {
return err
}
return nil
}
的println/Scanln並不意味着用於序列化。你可以實現'fmt.Scanner',但是你可以直接在你的Marshal方法中執行。 – JimB