Array(陣列)
陣列存放的是固定長度、相同型別的資料。
陣列宣告
-
var <陣列名> = [<長度>]<元素>{元素1,元素2}
var arr = [2]int{1,2}
或者
arr := [2]int{1,2}
-
var <陣列名> = [...]<元素型別>{元素1,元素2}
var arr = [...]int{1,2}
或者
arr := [...]int{1,2}
-
var <陣列名> = [...]<型別>{索引1:元素1,索引2:元素2}
var arr = [...]int{1:1,0:2}
或者
arr := [...]int{1:1,0:2}
陣列的每個元素在記憶體中都是連續存放的,每個元素都有一個下標,下標從0開始。
陣列長度可以省略,會自動根據{}中的元素來進行推導。
沒有初始化的索引,預設值是陣列型別的零值。
陣列迴圈
for i,v := range array {
fmt.Printf("索引:%d,值:%s\n",i,v)
}
- range 表示式返回陣列索引賦值給 i,返回陣列值賦值給 v。
- 如果返回的值用不到,可以用 _ 下劃線丟棄:
for _,v:= range array{
fmt.Printf("值:%s\n",i,v)
}
切片
切片和陣列型別,可以理解為動態的陣列,切片是基於陣列實現的,它的底層就是一個陣列。對於陣列的分割,便可以得到一個切片。
陣列生成切片
slice := array[start:end]
array := [5]string{"a","b","c","d","e"}
slice := array[2:5]
fmt.Println(slice) //[c d e]
注意:這裡包含索引2,但是不包含索引5的元素,即:左閉右開。
經過切片後,切片的索引範圍也改變了。
array[start:end] 中的 start 和 end 都是可以省略的,start 的預設值是 0 ,end 的預設值為陣列的長度。
array[:] 等價於 array[0:5]
切片修改
切片的值也可以被修改,這裡也可以證明切片的底層是陣列。
array := [5]string{"a","b","c","d","e"}
slice := array[2:5] //[c d e]
slice[1] = "f"
fmt.Println(slice) //[c f e]
fmt.Println(array) //[a b c f e]
修改切片,對應的陣列值也被修改了,所以證明基於陣列的切片,使用的底層陣列還是原來的陣列,一旦修改切片的元素值,底層陣列對應的值也會被修改。
切片宣告
使用 make 函式宣告切片
//宣告一個元素型別為string的切片,長度是4
slice := make([]string,4)
//長度是4,容量是8
slice1 := make([]srting,4,8)
切片的容量不能比切片長度小。
長度就是元素個數。
容量就是切片的空間。
上面例項在記憶體上劃分了一個容量為8的記憶體空間,但是隻是用了4個記憶體空間,剩餘的處於空閒狀態。當通過 append 往切片追加元素時,會追加到空閒記憶體上,剩餘空間不足時,會進行擴容。
字面量初始化切片
slice2 := []string{"a","b","c"}
fmt.Println(len(slice2),cap(slice2)) //3 3
Append
append 函式對一個切片進行追加元素:
slice3 := append(slice2,"d")
//追加多個元素
slice3 := append(slice2,"d","f")
//追加一個切片
slice3 := append(slice2,slice...)
小技巧:
在建立新切片時,最好讓長度和容量一樣,這樣追加操作的時候就會生成新的底層陣列,從而和原有陣列分離,就不會因為公用底層陣列導致修改內容的時候影響多個切片。
切片迴圈
切片迴圈與陣列一樣,也是使用 for range 方式。
Map (對映)
map 是一個無序的 k-v 鍵值對集合。其中 k 必須是相同型別。k 和 v 的型別可以不同。 k 的型別必須支援 == 比較運算子,這樣才可以判斷它是否存在,並保證唯一。
Map 宣告初始化
-
make:
mapName := make(map[string]int)
-
字面量:
mapName := map[string]int{"無塵":29}
如果不想建立的時候新增鍵值對,使用空大括號{}即可,切記不能省略。
Map 獲取、刪除
//新增鍵值對或更新對應的key的value
mapName["無塵"] = 20
//獲取指定key的value
age := mapName["無塵"]
獲取不存在的 k-v 鍵值對時,如果 key 不存在,返回的 value 是該值的零值,所以很多時候,需要先判斷 map 中的 key 是否存在。
nameAge := make([string]int)
nameAge["無塵"]=29
age,ok := nameAge["無塵"]
if ok {
fmt.Println(age)
}
- map 的 [] 操作返回兩個值
- 第一個是 value
- 第二個是標記該 key 是否存在,存在則為 true
delete()函式進行刪除
delete(nameAge,"無塵")
- delete 有兩個引數,一個是map,一個是要刪除的 key 。
遍歷 Map
nameAge["無塵"] = 29
nameAge["無塵1"] = 30
nameAge["無塵2"] = 31
for k,v := range nameAge{
fmt.Println("key is",k,"value is ",v)
}
- 對應 map ,for range 返回兩個引數,分別是 k 和 v。
小技巧:for range 遍歷 map 的時候,若使用一個返回值,則這個返回值是 map 的 key 。
Map 的大小
map 不同於切片,map 只有長度,沒有容量。可以使用 len 函式獲取 map 大小。
String 和 []byte
字串也是一個不可變的位元組序列,可以直接轉為位元組切片 []byte :
s:="Hello無塵小生"
bs := []byte(s)
string 不止可以直接轉為 []byte,還可以使用 [] 操作符獲取指定索引的位元組值。
字串是位元組序列,每一個索引對應一個位元組,在 UTF8 編碼下,一個漢字對應三個位元組。
如果把一個漢字當做一個長度計算,可以使用 utf8.RuneCountInString 函式。
for range 遍歷時,是按照 unicode 字元進行迴圈的,一個漢字佔一個長度。