這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
Time won't go back I won't turn back.
時光不會倒著走,我也不會再回頭。
其實這個問題其實是出現在參考型別( 此處是slice )上, 這個是 slice 的資料結構,它很簡單,一個指向真實 array 地址的指標 ptr ,slice 的長度 len 和容量 cap 。
結構圖解1
每次cap改變的時候指向array記憶體的指標都在變化, 在實際使用中,我們最好事先預期好一個cap,這樣在使用append的時候可以避免反覆重新分配記憶體複製之前的資料,減少不必要的效能消耗。
現在上執行個體,來看看坑所在:
package mainimport "fmt"import "time"func main() {ch := make(chan []byte, 10)go func() {for {select {case data := <-ch:fmt.Println(string(data))}}}()data := make([]byte, 0, 32)data = append(data, []byte("bbbbbbbbbb")...)ch <- data// fmt.Printf("%p\n", data)data = data[:0]// fmt.Printf("%p\n", data)data = append(data, []byte("aaa")...)ch <- datatime.Sleep(time.Second * 5)}
預測的運行結果:
bbbbbbbbbb
aaa
但是肯定是有坑的:
前面新起了一個協程來等待通道接受資訊, 主進程繼續執行, 當data傳遞給了通道之後, 立刻修改了data指向數組的值(第二次append), 所以通道第一次接收的值就已經改變了, 因為我們傳遞的是引用,不是實值型別。
解決方案呢就是加鎖 或者新變數拷貝。