2015-09-22 89 views
2

http://play.golang.org/p/RqScJVvpS7指數走出

package main 

import (
    "fmt" 
    "math/rand" 
    "encoding/binary" 
) 

func main() { 
    buffer := []byte{0, 0, 0, 0, 0, 0, 0, 0} 
    num := rand.Int63() 
    count := binary.PutVarint(buffer, num) 

    fmt.Println(count) 
} 

我有一段時間以前,這個工作時num只是一個遞增uint64,我用binary.PutUvarint但現在,這是一個隨機的Int64和binary.PutVarint我收到一個錯誤:

panic: runtime error: index out of range 

goroutine 1 [running]: 
encoding/binary.PutUvarint(0x1042bf58, 0x8, 0x8, 0x6ccb, 0xff9faa4, 0x9acb0442, 0x7fcfd52, 0x4d658221) 
    /usr/local/go/src/encoding/binary/varint.go:44 +0xc0 
encoding/binary.PutVarint(0x1042bf58, 0x8, 0x8, 0x6ccb, 0x7fcfd52, 0x4d658221, 0x14f9e0, 0x104000e0) 
    /usr/local/go/src/encoding/binary/varint.go:83 +0x60 
main.main() 
    /tmp/sandbox010341234/main.go:12 +0x100 

我在想什麼?我會認爲這是一個微不足道的變化......

編輯:我只是試圖擴展我的緩衝區數組。由於一些奇怪的原因,它的作品,我得到10count。怎麼可能? int64是64位= 8字節,對吧?

回答

7

引用的encoding/binary該文檔:

The varint functions encode and decode single integer values using a variable-length encoding; smaller values require fewer bytes. For a specification, see https://developers.google.com/protocol-buffers/docs/encoding .

所以binary.PutVarint()不是固定的,而是可變長度編碼。當通過int64時,大數字需要多於8個字節,小數字需要少於8個字節。由於您編碼的數字是一個隨機數,因此即使在其最高字節中也會有隨機位。

參見這個簡單的例子:

buffer := make([]byte, 100) 
for num := int64(1); num < 1<<60; num <<= 4 { 
    count := binary.PutVarint(buffer, num) 
    fmt.Printf("Num=%d, bytes=%d\n", num, count) 
} 

輸出:

Num=1, bytes=1 
Num=16, bytes=1 
Num=256, bytes=2 
Num=4096, bytes=2 
Num=65536, bytes=3 
Num=1048576, bytes=4 
Num=16777216, bytes=4 
Num=268435456, bytes=5 
Num=4294967296, bytes=5 
Num=68719476736, bytes=6 
Num=1099511627776, bytes=6 
Num=17592186044416, bytes=7 
Num=281474976710656, bytes=8 
Num=4503599627370496, bytes=8 
Num=72057594037927936, bytes=9 

可變長度編碼的本質是,少量使用更少的字節,但是這隻能達到如果反過來大數字可能會使用多於8個字節(大小爲int64)。

具體編碼的詳細信息在linked page

一個非常簡單的例子是:一個字節是8位。使用輸出字節的7位作爲「有用」位來編碼數據/編號。如果最高位是1,則意味着需要更多的字節。如果最高位是0,我們就完成了。您可以看到小數字可以使用1個輸出字節進行編碼(例如n=10),而對於每個7位有用數據,我們使用1個額外位,所以如果輸入數字使用所有64位,我們將最終以超過8個字節:需要10個組來覆蓋64個比特,所以我們需要10個字節(9個組只有9 * 7 = 63個比特)。

+0

但是'rand.Int63()'返回一個'int64',它的定義是8個字節,對嗎?怎麼可能需要10個? –

+2

@CoreyOgburn:Varint是一種可變長度編碼。你想'ByteOrder.PutUint64',或者''binary.Write'。 – JimB

+0

我在質疑我的理智。 int64,一個64位= 8字節的值如何得到10個字節? 「可變長度編碼」聽起來像它應該能夠存儲多達8個字節,如果它是一個小值,則可以少一些。 –