這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
學習筆記
1、arrayarray就是數組,它的定義方式如下:var arr [n]type在[n]type中,n表示數組的長度,type表示儲存元素的類型。對數組的操作和其它語言類似,都是通過[]來進行讀取或賦值:
var arr [10]int // 聲明了一個int類型的數組
arr[0] = 42 // 數組下標是從0開始的
arr[1] = 13 // 賦值操作
fmt.Printf("The first element is %d\n", arr[0]) // 擷取資料,返回42
fmt.Printf("The last element is %d\n", arr[9]) //返回未賦值的最後一個元素,預設返回0
由於長度也是數群組類型的一部分,因此[3]int與 [4]int是不同的類型,數組也就不能改變長度。數組之間的賦值是值的賦值,即當把一個數組作為參數傳入函數的時候,傳入的其實是該數組的副本,而不是它的指標。如果要使用指標,那麼就需要用到後面介紹的slice類型了。數組可以使用另一種:=來聲明
a := [3]int{1, 2, 3} // 聲明了一個長度為3的int數組
b := [10]int{1, 2, 3} // 聲明了一個長度為10的int數組,其中前三個元素初始化為1、2、3,其它預設為0
c := [...]int{4, 5, 6} // 可以省略長度而採用`...`的方式,Go會自動根據元素個數來計算長度
也許你會說,我想數組裡面的值還是數組,能實現嗎?當然咯,Go支援嵌套數組,即多維陣列。比如下面的代碼就聲明了一個二維數組:
// 聲明了一個二維數組,該數組以兩個數組作為元素,其中每個數組中又有4個int類型的元素
doubleArray := [2][4]int{[4]int{1, 2, 3, 4}, [4]int{5, 6, 7, 8}}
// 如果內部的元素和外部的一樣,那麼上面的聲明可以簡化,直接忽略內部的類型
easyArray := [2][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}}
2、slice在很多應用情境中,數組並不能滿足我們的需求。在初始定義數組時,我們並不知道需要多大的數組,因此我們就需要“動態數組”。在Go裡面這種資料結構叫sliceslice並不是真正意義上的動態數組,而是一個參考型別。slice總是指向一個底層array,slice的聲明也可以像array一樣,只是不需要長度。// 和聲明array一樣,只是少了長度var fslice []int接下來我們可以聲明一個slice,並初始化資料,如下所示:slice := []byte {'a', 'b', 'c', 'd'}slice可以從一個數組或一個已經存在的slice中再次聲明。slice通過array[i:j]來擷取,其中i是數組的開始位置,j是結束位置,但不包含array[j],它的長度是j-i。
// 聲明一個含有10個元素元素類型為byte的數組
var ar = [10]byte {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
// 聲明兩個含有byte的slice
var a, b []byte
// a指向數組的第3個元素開始,併到第五個元素結束,
a = ar[2:5] //現在a含有的元素: ar[2]、ar[3]和ar[4]
// b是數組ar的另一個slice
b = ar[3:5] // b的元素是:ar[3]和ar[4]
注意slice和數組在聲明時的區別:聲明數組時,方括弧內寫明了數組的長度或使用...自動計算長度,而聲明slice時,方括弧內沒有任何字元。
slice有一些簡便的操作
- slice的預設開始位置是0,ar[:n]等價於ar[0:n]
- slice的第二個序列預設是數組的長度,ar[n:]等價於ar[n:len(ar)]
- 如果從一個數組裡面直接擷取slice,可以這樣ar[:],因為預設第一個序列是0,第二個是數組的長度,即ar[:]等價於ar[0:len(ar)]
對於slice有幾個有用的內建函數:
- len 擷取slice的長度
- cap 擷取slice的最大容量
- append 向slice裡面追加一個或者多個元素
- copy 函數copy從源slice的src中複製元素到目標dst,並且返回複製的元素的個數
註:
append函數會改變slice所引用的數組的內容,從而影響到引用同一數組的其它slice。
但當slice中沒有剩餘空間(即(cap-len) == 0)時,此時將動態分配新的數組空間。返回的slice數組指標將指向這個空間,而原數組的內容將保持不變;其它引用此數組的slice則不受影響。
下面這個例子展示了更多關於slice的操作:
// 聲明一個數組
var array = [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
// 聲明兩個slice
var aSlice, bSlice []byte
// 示範一些簡便操作
aSlice = array[:3] // 等價於aSlice = array[0:3] aSlice包含元素: a,b,c
aSlice = array[5:] // 等價於aSlice = array[5:10] aSlice包含元素: f,g,h,i,j
aSlice = array[:] // 等價於aSlice = array[0:10] 這樣aSlice包含了全部的元素
// 從slice中擷取slice
aSlice = array[3:7] // aSlice包含元素: d,e,f,g,len=4,cap=7
bSlice = aSlice[1:3] // bSlice 包含aSlice[1], aSlice[2] 也就是含有: e,f
bSlice = aSlice[:3] // bSlice 包含 aSlice[0], aSlice[1], aSlice[2] 也就是含有: d,e,f
bSlice = aSlice[0:5] // 對slice的slice可以在cap範圍內擴充,此時bSlice包含:d,e,f,g,h
bSlice = aSlice[:] // bSlice包含所有aSlice的元素: d,e,f,g
slice是參考型別,所以當引用改變其中元素的值時,其它的所有引用都會改變該值,例如上面的aSlice和bSlice,如果修改了aSlice中元素的值,那麼bSlice相對應的值也會改變。從概念上面來說slice像一個結構體,這個結構體包含了三個元素:
- - 指標,指向數組中slice指定的開始位置
- - 長度,即slice的長度
- - 最大長度,也就是slice開始位置到數組的最後位置的長度
3、map格式為: map[keyType]valueTypemap的讀取和設定也類似slice一樣,通過key來操作,只是slice的index只能是`int`類 型,而map多了很多類型,可以是int,可以是string及所有完全定義了==與!=操作的類型。
// 聲明一個key是字串,值為int的字典,這種方式的聲明需要在使用之前使用make初始化var numbers map[string] int// 另一種map的聲明方式numbers := make(map[string]int)numbers["one"] = 1 //賦值numbers["ten"] = 10 //賦值numbers["three"] = 3fmt.Println("第三個數字是: ", numbers["three"]) // 讀取資料// 列印出來如:第三個數字是: 3
這個map就像我們平常看到的表格一樣,左邊列是key,右邊列是值使用map過程中需要注意的幾點:
- - map是無序的,每次列印出來的map都會不一樣,它不能通過index擷取,而必須通過key擷取
- - map的長度是不固定的,也就是和slice一樣,也是一種參考型別
- - 內建的len函數同樣適用於map,返回map擁有的key的數量
- - map的值可以很方便的修改,通過numbers["one"]=11可以很容易的把key為one的字典值改為11
map的初始化可以通過key:val的方式初始化值,同時map內建有判斷是否存在key的方式通過delete刪除map的元素:
// 初始化一個字典rating := map[string]float32 {"C":5, "Go":4.5, "Python":4.5, "C++":2 }// map有兩個傳回值,第二個傳回值,如果不存在key,那麼ok為false,如果存在ok為truecsharpRating, ok := rating["C#"]if ok {fmt.Println("C# is in the map and its rating is ", csharpRating)} else {fmt.Println("We have no rating associated with C# in the map")}delete(rating, "C") // 刪除key為C的元素
上面說過了,map也是一種參考型別,如果兩個map同時指向一個底層,那麼一個改變,另一個也相應的改變:
m := make(map[string]string)m["Hello"] = "Bonjour"m1 := mm1["Hello"] = "Salut" // 現在m["hello"]的值已經是Salut了