go中的slice坑

go中的slice坑

在進行項目中遇到了一些關於Go中的切片的坑,記錄下來,提醒自己

在進行項目調試的時候,發現第一次請求時,能夠拿到全部想要的結果。但是之後的所有請求,有一部分結果爲空。但是整個方法在進行測試的時候都是能夠通過的。不清楚錯誤是出在哪裏。仔細回查代碼,並沒有感覺到哪裏出現了問題。

在反覆檢查得都要爆炸的時候,突然感覺到了在一個方法中cipher []string作爲參數傳入應該會有問題。有了這個預感,就去驗證自己的感覺是否是正確的。在對方法調用查詢的時候發現,我是使用了一個全局的切片作爲參數傳入了該方法。於是做出猜想,普通的數組的傳遞是值傳遞,會不會是切片的傳遞其實是個引用傳遞。這樣就能很好的解釋了爲什麼 ,第一次請求能夠拿到數據,之後的請求無法拿到數據:在這個方法中我對切片中的數據有移除的操作。如果是引用傳遞,那麼這次移除操作操作的對象就是我所定義的全局的切片,導致全局的切片中的內容全部移除。之後的操作,全局切片中的內容就是空的。講道理的,那麼第二次極其以後的操作爲空也就說的通了。但到底是不是猜測的那樣,寫了的demo來說明:

func main() {
    a := []int{1, 2, 3, 4}
    b := [4]int{1, 2, 3, 4}
    fmt.Println("origin slice: ", a)
    fmt.Println("origin array:", b)
    sliceTest(a)
    arrayTest(b)

    fmt.Println("change slice: ", a)
    fmt.Println("change array: ", b)
}

func sliceTest(slice []int) {
    slice[0] = 5
}

func arrayTest(array [4]int) {
    array[0] = 5
}

結果:

img

可以發現,通過sliceTest方法的確是修改了原始的a切片中的內容。雖然已經可以確定問題的原因,但是還是去網上驗證一下。在segmentfault中的這篇關於Go語言中數組的參數傳遞問題寫一個程序證明切片是值類型而map是引用類型的回答應該說的比較清楚了。講道理,go的所有的傳遞都是值傳遞,slice是個值類型,但是表現出了引用語義。

問題既然發現了那就要進行解決。在學習go的時候記得go內置了一個copy()函數,用於複製內容。於是我很自然的想到了var一個切片變量,然後使用copy() 函數把傳入的切片中的內容複製到這個新創建的變量中。想法是美好的,現實是殘酷的。這樣寫的結果是:var出來的變量中的內容是空的。不能理解爲什麼是這個結果,於是去google了一把。在Why can not I copy a slice with copy in golang?(這個需要梯子)的回答中也講明瞭:copy(dst,src) 複製min(len(dst), len(src))個元素,因爲我們是直接使用var出來的dst的切片,因此len(dst)爲0,即該方法什麼都不做。因此不要使用var 申明一個變量,而是使用make()函數直接創建一個和src一樣大小的切片:

arr := []int{1, 2, 3}
tmp := make([]int, len(arr))
copy(tmp, arr)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章