文章目錄
- 寫在前面
- 數組
- 切片
- Map
寫在前面
前面的文章介紹了Go的一些基本類型,本文開始涉及Go的一些容器類型,它們都是可以包含多個元素的資料結構,如數組、切片、map
數組
數組是具有相同類型且長度固定的一組元素集合,定義的格式:
var 數組名 [數組長度]數組元素類型
,下面聲明一個長度為5的int型數組
arr
- 數組元素可以是任意的原始類型,例如整型、字元串等,一個數組内所有元素的類型必須是相同的
- 數組的長度必須是一個常量表達式,且是一個非負整數,特别注意數組的長度也是數組類型的一部分,是以不同長度的數組是不同的類型。數組的長度在聲明時就要給出。擷取數組長度用内置函數
len(arr)
- 當聲明數組時所有的元素都會被初始化為預設的類型零值,我們也可以在聲明數組的同時進行初始化
還可以在初始化時僅初始化指定元素var arr = [5]int{1, 2, 3, 4, 5} a := [3]int{1, 2, 3}
- 如果聲明數組時不想直接寫長度,可以用
代替,編譯器會自動生成滿足最低長度要求的數組...
- 通過
循環來周遊操作數組for
var arr [5]int for i := 0; i < len(arr); i++ { arr[i] = i * 2 } for i, v := range arr { fmt.Println("index: ", i, "value: ", v) }
- 數組是一種值類型(不像C/C++那樣是指向首元素的指針),可以通過
來建立數組,不過它傳回的是指向該數組的指針new
注意區分指向數組的指針和指針數組d := new([4]int) fmt.Println(d) //&[0,0,0,0] fmt.Println(*d) //[0,0,0,0]
e := [5]int{1, 2, 3, 4, 5} var p *[5]int = &e //p為指向數組e的指針 &[1,2,3,4,5] x, y := 1, 2 z := [2]*int{&x,&y} //z是一個指針數組
- 多元數組
h := [2][3]int{ {1, 1, 1}, {2, 2, 2} }
- 數組可以使用
或==
來比較!=
f := [2]int{1, 2} g := [2]int{1, 2} fmt.Println(f == g) //true
切片
切片(slice)是對某個數組的一段連續片段的引用(該數組我們稱為相關數組,該片段可以是整個數組,也可以是數組中的某一段),是以切片是一個引用類型。切片底層實作是數組,它與數組的關系如下圖:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL90zdOBTRE10dFRUYoh2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLwgjN1QTOxYTM1ETNwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
多個slice可以指向同一個底層相關數組,此時其中一個值改變會影響全部的值
- 切片是一個可變長的數組,它的長度可以動态修改,可以用
來擷取切片的長度。切片還有另外一個屬性容量,表示切片可以達到的最大長度,可以用len()
來擷取。切片的容量等于切片的長度+相關數組中在切片之後剩下的的長度。是以切片的長度小于等于切片的容量。cap()
- 切片的容量是預先配置設定的,如果在運作的過程中,切片的長度超過了原來配置設定的容量,則會重新配置設定一個空間更大的數組,然後将值都拷貝過去
- 切片的聲明格式:
,這裡不需要指定長度,如果是數組則必須指定長度或者用var 切片名 []元素類型
替代...
- 切片可以通過底層相關數組切取,也可以用
直接建立,還可以通過已有的切片來生成make
- 通過數組生成
arr := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} s1 := arr[2:5] //切取數組arr索引從2~4這一段(即[3,4,5]),注意索引值不包括5 s2 := arr[:] //切片為整個arr數組 s3 := arr[5:] //切取從索引5開始到末尾,即[6,7,8,9,10]
- 通過
make
建立
格式:
,其中make([]type, len, cap)
可以省略,省略則預設和cap
相同len
s4 := make([]int, 3, 20) s5 := make([]int, 3)
- 通過切片生成,這種方式有時也被稱之未稱未切片重組reslice
需要注意的是,新的切片的索引不能超過原切片的容量,否則會引發編譯錯誤,而不是重新配置設定數組sa := []int{1, 2, 3, 4, 5} sb := sa[1:4] //[2,3,4],len:3,cap:4 sc := sb[1:4] //[3,4,5],len:3,cap:3
- 通過數組生成
-
在切片上追加元素(append)
如果要在切片上添加新的元素,可以使用
函數,用法為append
append(被追加元素的slice, 追加的元素...)
注意,如果追加後的長度未超過原slice的容量,則傳回原始的slice,如果超過了,則重新配置設定空間更大的數組并拷貝原始資料s1 := make([]int, 3, 6) s1 = append(s1, 1, 2, 3) //[0,0,0,1,2,3],還是傳回原來的slice (沒有超過原來cap) s1 = append(s1, 1, 2, 3) //[0,0,0,1,2,3,1,2,3],傳回的是一個新的slice(已經超過了cap,重新配置設定底層數組)
-
拷貝slice
可以使用
函數将一個切片拷貝到另外一個切片中,用法copy
copy(目标slice, 被拷貝的slice)
sc1 := []int{1, 2, 3, 4, 5} sc2 := []int{6, 7, 8} copy(sc1, sc2) fmt.Println(sc1) //[6 7 8 4 5] copy(sc2,sc1) fmt.Println(sc2) //[6,7,8] copy(sc2[0:2], sc1[3:5]) //指定具體位置 fmt.Println(sc2) //[4 5 8]
Map
Map是Go裡面的鍵值對集合,由key-value對組成,給定key,可以快速定位到對應的value。也被稱為字典、哈希表等
- map中的key可以是任意能夠用
或者==
操作符比較的類型,比如!=
,string
、int
等,不能是函數、map、切片;value可以是任意類型float
- map的聲明方式
var map變量名 map[key類型]vlaue類型
特别注意,map必須要初始化才能使用,即如果用上面這種方式,必須要有初始化的語句var m map[int]string //聲明 m = map[int]string{1:"a", 2:"b"} //初始化
,否則将報錯。當然如果覺得太繁雜,可以使用下面的map1 = map[keyType]ValueType{}
語句來替代,更加簡潔(主要是因為使用前需要先配置設定好記憶體空間給map,使用初始化語句或者make
語句才能實作空間的配置設定)make
- map也屬于引用類型,聲明的時候不需要知道長度,可以動态增加,可以使用
來建立make
var m1 map[int]string = make(map[int]string) m2 := make(map[int]string) //簡要寫法 m1[1] = "ok" //插入 (1 : ok)的key-value m2[1] = "good"
建立還可以指定容量,make
,make(map[key類型]value類型,cap)
為容量,可以省略。超出容量會自動擴容,但為了性能還是盡量提供一個大概的初始值。cap
- 擷取指定key的value
(擷取key為1的value)a:=m[1]
- 插入一個k-v對(或對指定key進行修改)
m[1]="ok"
-
判斷鍵值對是否存在
上面擷取指定key的值
還有另外一種用法:map[key]
,即傳回兩個值,第二個值value,isPresent = map[key]
是布爾類型,如果該key存在,該值為isPresent
,且true
為該key對應的值;如果key不存在,則value
為isPresent
,且false
為空值。value
if value, ok := map1[key1];ok{ fmt.Println(value) }
- 删除指定key的鍵值對
delete(map1, key1)
- 使用
對map進行周遊for-range
如果指向擷取key或者value,可以這麼使用map1 := make(map[int]string) map1[1] = "a" map1[2] = "b" map1[3] = "c" for key, value := range map1 { fmt.Println(key,value) }
需要注意的是,for key := range map1 { fmt.Println(key) } for _, vlaue := range map1 { fmt.Println(value) }
中獲得的key和value值都是副本,直接對這兩個值進行修改并不會對原來的map有影響。需要用for
才能真正改變map中的值map[key]
- map類型的切片:注意需要使用兩次
,第一次配置設定切片,第二次配置設定切片中每個map元素make
sm := make([]map[int]string, 5) for i := range sm { sm[i] = make(map[int]string,1) sm[i][1]="ok" }
- 嵌套map的使用:即map中value也是map類型,這種情況同樣需要注意每一個嵌套的map也需要進行
之後才能使用(初始化配置設定空間)make
var m2 map[int]map[int]string m2 = make(map[int]map[int]string) m2[1] = make(map[int]string) //value中嵌套的map也需要進行初始化 m2[1][1] = "ok1"