這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
在go語言的學習中,少不了接觸的就是數組和數組切片,並且這兩者的使用也是非常頻繁的。因此如果不能進行很好的理解,或許很容易犯錯。那麼在go中,數組和數組切片都有什麼特點,又是怎麼聲明賦值的,如何使用的呢,下面我就自己的理解總結一下,個人總結可能不全或者有錯,望指點。
一、數組和數組切片的特點
數組是什麼就不用多說了,作為開發人員,這是經常會用到的東西,相信大家都有自己的理解。現在先總結一下數組的特點
1. 數組的長度在定義之後就不可被更改
2. 數組聲明時的長度必須為常量或常量運算式,即可以在編譯器確定長度,分配記憶體
3. 數組的下標從0開始,最後一個元素的下標為(長度-1),即在go中可以寫為 len(arr)-1
4. go語言的數組是實值型別,在作為參數傳遞時會做數組的複製操作。因此作為參數傳遞的時候,被修改的內容不影響原來的數組內容,隻影響傳入函數內的副本
數組切片:是go提供的一種新型的資料類型,它在go語言中的使用有C或C++中的指標的功效。但由於它又不同於指標,所以沒有C或C++中語言的指標操作方式。數組切片的底層是通過數組實現,很容易聯想到C++的vector。
1. 與數組不同,數組切片的長度是可變的,即可以動態分配記憶體空間。但在每次新分配空間的時候,即會對當前的元素進行一次複製
2. go語言提供了內建函數copy用於將內容從一個數組切片複製到另外一個數組切片,但如果兩個數組切片的長度不一樣,則會按照較小的數組切片的個數進行複製。
3. 數組切片與數組一樣,其下標從0開始,最後一個元素的下標為(長度-1),即在go中可以寫為 len(arr)-1
4. go語言提供cap()內建函數可以獲得數組切片分配的空間大小,該值的返回可能與len()返回的大小不同
5. 數組切片提供建立時指定長度和預留儲存空間。在知道數組切片最終能用到的長度時,可以避免切片擴容所引發的記憶體的申請釋放與複製。
6. 數組切片作為參數傳遞時,不會出現記憶體的複製操作,在函數中如果修改了傳入的切片的參數,可以直接修改原數組切片的內容。
二、數組與數組切片的使用
(一) 聲明與建立
數組的定義初始化比較簡單,如下:
1. var arr [10]int//聲明長度為10,類型為int的數組。也可以聲明多維陣列,如:var twod [10][100]int。也可以定義複雜類型數組,如:var st_arr [100]struct {x, y int }
arr[1] = 1 //根據索引賦值
2. arr := [5]int{1,2,3,4,5}//聲明並初始化數組
3. var arr [5]int = [5]int{1,2,3,4,5}//定義並初始化數組
數組切片的定義與初始化,如下:
1. 基於數組建立
arr := [10]int{1,2,3,4,5}
var slc1 []int = arr[:]//基於數組全部元素建立切片
var slc2 []int = arr[:5]//基於前五個元素建立切片
var slc3 []int = arr[5:]//基於從第五個元素建立切片
var slc4 []int = arr[2:8]//基於從第二個到第八個元素建立切片
以上幾種建立切片的方式,都是基於一種建立規則:基於arr[first:last]這種方式建立數組切片
2. 直接建立
slice1 := make([]int, 5)//建立一個初始元素個數為5的數組切片,元素初始值為0
slice2 := make([]int, 5, 10)//建立一個初始元素個數為5的數組切片,元素初始值為0,並預留10個元素的儲存空間
slice3 := []int{1, 2, 3, 4, 5}//直接建立並初始化包含5個元素的數組切片
3. 基於數組切片建立數組切片
基於數組切片建立數組切片和基於數組建立切片基本相同。但新建立的切片元素個數可以超過舊切片所包含的元素個數,該操作要求新建立切片的元素個數不超過舊切片的容量個數。如:
slice1 := make([]int, 5, 10)
slice2 := slice1[:6]
(二)遍曆元素
在go中,無論是數組還是數組切片,都提供了兩種相同的遍曆方式:
1. 使用傳統的for遍曆:
for i := 0; i < len(arr); i++ {
fmt.Println("arr[",i,"] is ", arr[i])
}
2. 使用range關鍵字:
for i, v := range arr {
fmt.Println("arr[",i,"] is ", v)
}
(三) 長度擷取
對於數組和數組切片,go語言提供了內建函數len(),使用方式len(arr),返回當前數組或數組切片的長度。對於數組切片,go語言提供內建函數cap()擷取數組切片的容量
(四)添加元素
對於數組定長,因此沒有添加元素的功能。但數組切片因為動態記憶體的問題,可以提供追加元素。在go語言中提供了內建函數append作為數組切片的元素追加。有以下兩種使用方式:
1. 直接追加元素:
slice1 := []int{1,2,3,4}
slice1 = append(slice1, 5, 6, 7)// append的第一個參數是基於的數組切片。第二個參數是不定參數,可以追加多個元素
2. 數組切片追加數組切片:
slice1 := []int{1,2,3,4}
slice2 := []int{5,6,7,8}
slice1 := append(slice1, slice2…)//這裡要特別注意的是:在第二個數組切片後面需要加三個點,否則會編譯錯誤。主要原因是append第二個參數起都是待追加的元素,而加上三個點的作用就是把slice2的元素按照元素內容列表傳入,而不是以切片作為參數傳入。
(五)作為參數傳遞
1. 數組作為參數
func sort(arr [10] int) {
...
}
該函數的調用要如下:
arr1 := [10]int{8,6,5,4,7,3,9,1,2,10}
arr2 := [5]int{4,2,3,5,1}
slice1 := []int{8,6,5,4,7,3,9,1,2,10}
sort(arr) //編譯正常,但由於數組穿參屬於值傳參,在傳參的時候會進行數組複製,因此只修改了sort內部的arr的值,未修改arr1的實際元素值內容
sort(arr2) //編譯錯誤,對於go而言,[10]int 和[5]int 是兩種不同的資料類型
sort(&arr) //編譯錯誤,對於C或C++而言,函數參數定義為int arr[10]這種實際是定義了數組的指標傳入。但go語言中,數組指標和數組是兩種完全不同的類型
sort(slice1)//編譯錯誤,同樣是因為類型不同
2. 數組切片作為參數
func sort(arr []int) {
...
}
arr1 := [10]int{8,6,5,4,7,3,9,1,2,10}
slice1 := []int{8,6,5,4,7,3,9,1,2,10}
sort(arr)//編譯錯誤,類型不同
sort(slice1)//編譯正確,且在sort中對於slice的修改會直接修改到原始的slice。