Go slice切片的「陷阱」和本質

文章說明

總結了go語言中切片slice的特殊性和使用時的注意事項。數組

我的理解,不足之處歡迎指出。bash

slice:切片,是go語言中一種經常使用的數據結構,基於數組構建,表示相同數據類型的集合。數據結構

數組

Go中數組類型表示固定長度的相同類型的數據的集合,數據在內存中連續存儲,能夠經過下標索引,可是又有特殊的地方:app

  • 數組是值類型,一個數組變量表示整個數組,而不是指向數組的首元素的指針,這和C語言不一樣。
  • 將數組賦值給另外一個數組,或者數組做函數參數傳遞時,會將數組的所有數據拷貝一份過去而不是傳遞一個指針。
  • 數組類型包括長度,即[5]int和[10]不是一種類型。

因此Go語言中使用數組傳遞數據效率很低,一般使用切片。函數

切片

切片是一個數組片斷的描述,包含了指向數組片斷的指針,片斷的長度len和容量cap(數組片斷的最大長度),可是切片自己並非真正的指針類型ui

切片的特性

  1. 能夠自動擴容 使用append()向切片追加數據,數據是被添加到切片指向的片斷末尾,長度等於容量時切片就會自動擴容,擴容的細節後面的文章再討論。
  2. 切片之間賦值或者切片做函數參數傳遞時,是將指向數組片斷的指針傳遞過去,因此改變一個會影響另外一個。

切片的陷阱

切片做函數參數傳遞或淺拷貝時,之因此改變一個切片的數據會影響另外一個切片,是由於兩個切片中中包含了指向同一數組片斷的指針。spa

一切看似正常?可是當一個切片發生擴容時,會將當前切片內的數據複製到另外一片內存區域,該切片的數組片斷的地址發生改變,因此當切片擴容時修改一個切片的數據時不會再影響到另外一個切片!此時只能經過傳遞切片自己的地址來解決。指針

擴容時出錯的代碼以下:code

package main

import "fmt"

func testSlice(slice []int) {
slice = append(slice, 6, 7, 8, 9, 10)
fmt.Println("testSlice:",slice)
}
func main() {
slice := []int{1, 2, 3, 4, 5}

	testSlice(slice)
fmt.Println("main:",slice)
}
複製代碼

切片的本質

因此,切片不是指針類型,切片數據類型是包含指向一個數組片斷的指針,和當前數組片斷的長度,以及當前數組最大容量的一種複合數據結構索引

相關文章
相關標籤/搜索