slice的append操作注意事項

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

如果不能很好的理解slice和slice的append操作,把slice作為參考型別傳參,會導致遺失資料
先上一個例子:

package mainimport "fmt"type DbItem struct {    Id  int16    Cnt int32}func combineItem(itemList []DbItem, id int16, cnt int32) {    item := DbItem{Id: int16(id), Cnt: int32(cnt)}    itemList = append(itemList, item)    fmt.Printf("combineItem itemList addr[%p]  cap[%d] len[%d] values: %v \n", itemList, cap(itemList), len(itemList), itemList)}func main() {    itemList := make([]DbItem, 1, 5)    combineItem(itemList, int16(1), int32(2))    fmt.Printf("1.cap沒有擴容的情況 itemList addr[%p] cap[%d] len[%d] values: %v \n", itemList, cap(itemList), len(itemList), itemList)    itemList = make([]DbItem, 5, 5)    combineItem(itemList, int16(1), int32(2))    fmt.Printf("2.cap被擴容,新DbItem追加在slice最後 itemList addr[%p] cap[%d] len[%d] values: %v \n", itemList, cap(itemList), len(itemList), itemList)    itemList = make([]DbItem, 5, 5)    combineItem(itemList[:1], int16(1), int32(2))    fmt.Printf("3.cap沒被擴容,新DbItem追加在slice中間 itemList addr[%p] cap[%d] len[%d] values: %v \n", itemList, cap(itemList), len(itemList), itemList)}

運行結果:
combineItem itemList addr[0xc4200480f0] cap[5] len[2] values: [{0 0} {1 2}]
1.cap沒有擴容的情況 itemList addr[0xc4200480f0] cap[5] len[1] values: [{0 0}]
combineItem itemList addr[0xc42003e050] cap[10] len[6] values: [{0 0} {0 0} {0 0} {0 0} {0 0} {1 2}]
2.cap被擴容,新DbItem追加在slice最後 itemList addr[0xc420048120] cap[5] len[5] values: [{0 0} {0 0} {0 0} {0 0} {0 0}]
combineItem itemList addr[0xc420048150] cap[5] len[2] values: [{0 0} {1 2}]
3.cap沒被擴容,新DbItem追加在slice中間 itemList addr[0xc420048150] cap[5] len[5] values: [{0 0} {1 2} {0 0} {0 0} {0 0}]

當slice_c=append(slice_a,slice_b)中len(slice_a)+len(slice_b)<=cap(slice_a)時不會擴容,否則會被擴為cap(slice_a)的兩倍,如果slice len大於1024了,會擴容四分之一cap。具體實現源碼如下:

newcap := old.capif newcap+newcap < cap {    newcap = cap} else {    for {        if old.len < 1024 {            newcap += newcap        } else {            newcap += newcap / 4        }        if newcap >= cap {            break        }    }}

從例2可以看見,append返回的slice指向了個新的地址。但是即使沒擴容,slice指向同一個地址的情況下,為何slice_c還是不等於slice_a呢?其實slice不是單純一個指標,而是個C的struct實現的:

struct    Slice{    // must not move anything    byte*    array;        // actual data    uintgo    len;        // number of elements    uintgo    cap;        // allocated number of elements};

在$GOROOT/src/pkg/runtime/runtime.h可以看見源碼。
在沒擴容的情況下,傳入slice_a的資料改變是會影響函數外的slice_a的值的,因為他們的byte*指向同一個地址。
擴容的情況下就沒有這個影響了。無論擴容與否,slice的值還取決於len,所以即使slice的byte*指向同一地址,打出來的結果還是不一樣的。所以當函數裡面有append,千萬別把slice作為參考型別的參數用了!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.