數組:
數組是一種數據類型元素的組合。在Go語言中,數組從聲明時就確定,使用的時候可以修改數組中的成員,但是數組的大小時不可以變化的
// 定義一個長度爲3元素類型爲int的數組a
var a [3]int
數組定義:var 數組變量名 [元素數量] T
數組的長度必須時常量,並且長度是數組類型的一部分。一旦定義了,長度不能變。[5]int和[10]int是不同的類型
數組可以通過下標進行訪問,下標是從0開始的,最後一個元素的下標是len-1,訪問越界(下標在合法的範圍之外),則會觸發訪問越界,會panic
數組的初始化:
1、初始化數組時可以使用初始化列表來設置數組元素的值
func main() { var testArray [3]int //數組會初始化爲int類型的零值 var numArray = [3]int{1, 2} //使用指定的初始值完成初始化 var cityArray = [3]string{"北京", "上海", "深圳"} //使用指定的初始值完成初始化 fmt.Println(testArray) //[0 0 0] fmt.Println(numArray) //[1 2 0] fmt.Println(cityArray) //[北京 上海 深圳] }
2、按照上面的方法每次都要確保提供的初始值和數組長度一致,一般情況下我們可以讓編譯器根據初始值的個數自行推斷數組的長度
func main() { var testArray [3]int var numArray = [...]int{1, 2} var cityArray = [...]string{"北京", "上海", "深圳"} fmt.Println(testArray) //[0 0 0] fmt.Println(numArray) //[1 2] fmt.Printf("type of numArray:%T\n", numArray) //type of numArray:[2]int fmt.Println(cityArray) //[北京 上海 深圳] fmt.Printf("type of cityArray:%T\n", cityArray) //type of cityArray:[3]string }
3、我們還可以使用指定索引值的方式來初始化數組
func main() { a := [...]int{1: 1, 3: 5} fmt.Println(a) // [0 1 0 5] fmt.Printf("type of a:%T\n", a) //type of a:[4]int }
遍歷數組:
func main() { var a = [...]string{"北京", "上海", "深圳"} // 方法1:for循環遍歷 for i := 0; i < len(a); i++ { fmt.Println(a[i]) } // 方法2:for range遍歷 for index, value := range a { fmt.Println(index, value) } }
多維數組:
Go語言是支持多維數組的,我們這裏以二維數組爲例(數組中嵌套數組)
二維數組的定義:
func main() { a := [3][2]string{ {"北京", "上海"}, {"廣州", "深圳"}, {"成都", "重慶"}, } fmt.Println(a) //[[北京 上海] [廣州 深圳] [成都 重慶]] fmt.Println(a[2][1]) //支持索引取值:重慶 }
二維數組的遍歷
func main() { a := [3][2]string{ {"北京", "上海"}, {"廣州", "深圳"}, {"成都", "重慶"}, } for _, v1 := range a { for _, v2 := range v1 { fmt.Printf("%s\t", v2) } fmt.Println() } }
slice:
在很多應用場景中,數組並不能滿足我們的需求。在剛開始定義數組的時候,我們並不知道需要多大的數組,所以這時候我們就需要動態數據了,在Go語言中稱這種數據結構叫slice
slice並不是真正意義上的動態數組,而是一個引用類型。slice總是指向一個底層的array,slice的聲明也可以像array一樣,只是不需要長度
// 和聲明array一樣,只是少了長度 var fslice []int
slice := []byte {'a', 'b', 'c', 'd'}
slice可以從數組或者一個已經存在的slice中再次聲明。slice通過array[i:j]來獲取,其中i是數組的起始位置,j就是結束位置,但是不包含array[j],它的長度是j-1
// 聲明一個含有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]
ps:slice和數組在聲明的時候的區別:聲明數組的時候,方括號內寫明瞭數組的長度使用...自動計算長度,而聲明slice的時候,方括號裏面是沒有任何字符的
- slice中默認的起始位置是0, ar[:n]等於ar[0:n]
- slice的第二個序列默認是數組的長度,ar[n:]等價於ar[n:len(ar)]
- 如果一個數組裏面直接獲取slice,可以使用ar[:],因爲默認第一個序列是0,第二個是數組的長度
slice是引用類型,所以當引用改變其中元素的值的時候,其它的所有引用都會作出相應的改變,從概念上來說slice更像是一個結構體,這個結構體主要包含了指針、長度以及最大長度
指針:指向數組中slice指定的開始位置
長度:slice的長度
最大長度:也就是slice開始位置到數組的最後位置的長度
slice中的內置函數:
len:獲取slice中的長度
cap:獲取slice的最大容量
append:像slice中追加一個或者多個元素,然後返回一個和slice一樣類型的slice
copy:從源slice的src中賦值元素到目標的dst,並且返回複製的元素的個數
ps:append函數會改變slice所引用的數組的內容,從而影響到引用同一個數組的其它的slice。但當slice沒有剩餘空間的(cap-len) == 0的時候,此時將動態分配新的數組的空間。返回slice數組指針將指向這個空間,而原數組的內容將保持不變;其它引用此數組的slice則不受影響
從Go1.2開始slice支持了三個參數的slice,之前我麼一直採用的這種方式在slice或者array基礎上來產生一個新的slice
map:
map也就是python中的字典的概念格式是:map[keyType]valueType
map的讀取和設置也類似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"] = 3 fmt.Println("第三個數字是: ", numbers["three"]) // 讀取數據 // 打印出來如:第三個數字是: 3
這個map就像我們平常看到的表格一樣,左邊一列是key,右邊一列是值
使用map的過程中需要注意的點:
- map是無序的,每次打印出來的map是會不一樣的,他不能通過index來取值,而必須通過對應key來獲取
- map的長度是不固定的,也就是和slice一樣的,也是一種引用類型
- 內置的len函數同樣適用於map,返回的是map擁有的key的數量
- map的值可以很方便的進行修改,通過對應的key就可以直接改成你想要的內容了,這個和python中的字典很類似
map的初始化可以通過key:value的方式來進行,通過map內置有判斷是否存在key的方式
通過delete刪除map的元素
// 初始化一個字典 rating := map[string]float32{"C":5, "Go":4.5, "Python":4.5, "C++":2 } // map有兩個返回值,第二個返回值,如果不存在key,那麼ok爲false,如果存在ok爲true csharpRating, 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 := m m1["Hello"] = "Salut" // 現在m["hello"]的值已經是Salut了
make、new操作:
make用於內建類型(map、slice、channel)的內存分配。new用於各種類型的內存的分配
內建函數new本質上跟其它語言中的同名函數功能一樣:new(T)分配了一個零值填充的T類型的內存空間,並且返回一個內存地址。用Go的術語來說就是返回了一個指針,指向了新分配的類型T的零值
new返回指針
內建函數make(T, args)與new(T)有着不同功能,make只能創建slice、map和channel,並且返回一個有初始值(非零)的T類型,而不是*T。本質上來講,導致這三個類型有所不同的原因是指向數據結構的引用在使用前必須被初始化。比如一個slice是一個包含指向數據結構(內部包含array)的指針、長度以及最大容量的三個描述符;在這些項目被初始化之前,slice爲nil,對於slice、map、channel來說,make初始化了內部數據結果,填充了適當的值
make返回初始化後的(非零)值
零值
關於"零值",所指並非是空值,而是一種變量未填充以前的默認值,通常是0。