1、陣列
陣列的定義: var name [length] type
舉個例子: var name [5] int
當中括號內沒有length,就表示陣列的長度是不確定的,這種陣列叫做切片。
1.1、陣列的基本用法
fmt.Println(name),可以列印陣列的所有元素
陣列的長度是固定的
陣列的遍歷:
for _, value := range name{
fmt.Prinntln(value)
}
1.2、陣列初始化
//多种初始化方式
var name [5] int = [5]int{1, 2, 3, 4, 5}
var name = [5]int{1, 2, 3, 4, 5}
name := [5]int{1, 2, 3, 4, 5}
//只初始化部分元素
name := [3]int{2:3}
//前面的都为0,name[2] = 3
//数组的长度是不确定的
name := [...]int{1, 2, 3, 4, 5}
name := [...]int{1, 2, 3}
相同型別,長度相同的資料可以相互賦值,字串型別的可以相互比較
1.3、多維陣列
//基本定义方式
var name [3][4] string
name[0] = [4]string{"a", "b", "c", "d"}
name[0][0] = "a"
2、切片
切片就是沒有長度的陣列,切片的長度是不固定的,切片是陣列的一個引用,切片是引用型別。
2.1、切片的基本用法
2.1.1、切片的定義
var name []string
fmt.Printf(%T, name)
//输出结果为[]string,本质是切片
2.1.2、切片增加元素
// 使用append来增加元素,注意书写的格式
name = append(name, "a")
2.2、切片的初始化
初始化一共有三種方式
1、陣列直接建立
2、使用string{}
3、使用make
// 第一种
allName := [5]string{"aaa", "bbb", "ccc", "ddd", "eee"}
nameSlice := allName[0:2] // "左闭右开,包含0,不包含2"
//第二种
allName := []string{"aaa", "bbb", "ccc", "ddd", "eee"}
//在切片上也可以进行切片创建
//第三种
//第一个参数是切片的类型,第二个参数是预分配的空间(长度)
allName := make([]string, 5)
2.3、切片的元素訪問
allName := []string{"aaa", "bbb", "ccc", "ddd", "eee"}
sliceName := allName[start:end] //左闭右开
//如果没有end,默认是到最后一个元素
//没有start,有end,默认是从第一个元素开始到end之前的元素
//冒号一定存在
2.4、切片中的省略號

再append得使用過程中,新增的元素可以是多個
可以透過直接新增元素的方式加入
也可以透過使用陣列或者切片加省略號的方式加入(透過加入省略號將原來的元素打散)
// 直接列出元素的情况
name := []string{"aaa", "bbb", "ccc", "ddd", "eee"}
name = append(name, "fff", "ggg", "hhh")
// 通过切片加入的情况
name := []string{"aaa", "bbb", "ccc", "ddd", "eee"}
name2 := []string{"fff", "ggg", "hhh"}
name = append(name, name2...)
// 通过数组加入的情况
name := []string{"aaa", "bbb", "ccc", "ddd", "eee"}
name2 := [3]string{"fff", "ggg", "hhh"}
name = append(name, name2[:]...)
2.5、切片的元素刪除和複製
2.5.1、刪除元素
切片的刪除操作是append或者其他重新生成slice的方式進行
// 切片的删除操作
name := []string{"aaa", "bbb", "ccc", "ddd", "eee"}
// 删除一个中间的元素
newName = append(name[:2], name[3:]...)
// 删除后面的元素
newName := name[:3]
newName = append(name[:3])
2.5.2、複製元素
複製也有多種方式
name := []string{"aaa", "bbb", "ccc", "ddd", "eee"}
// 第一种切片赋值
name2 := name[:]
// 第二种使用copy函数
var name3 = make([]string, len(name))
copy(name3, name)
不同切片複製的方式會有不同的效果
示例如下:

從圖中可以看出,改變原來的切片,切片賦值的方式,會改變新的切片,而copy函式的方式,不會改變新的切片。
本質上是因為切片賦值的方式,是將原來的切片的地址賦值給了新的切片,而copy函式的方式,是將原來的切片的元素複製到了新的切片中(地址是新分配的)。
2.6、切片的底層儲存原理
go的slice在函式引數傳遞的時候是值傳遞還是引用傳遞
本質上是值傳遞,但是呈現出引用的效果,這涉及slice的底層原理
在go中,slice的底層是一個結構體,結構體中有三個欄位,分別是指向底層陣列的指標,切片的長度和切片的容量
2.6.1、切片的底層結構
// slice的底层结构如下:
type slice struct {
array unsafe.Pointer //用来存储实际数据的数组指针只想一块连续的内存
len int //切片中元素的数量
cap int //array数组的长度
}
2.6.2、切片的擴容機制
剛開始的時候slice會申請一個較大的容量,擴容是一個非常麻煩的過程:

擴容的時候剛開始是成倍的擴容,等到空間變大時擴容會減緩
2.6.3、切片的引數傳遞機制
在引數傳遞的時候會將原來的結構體整體複製一份,多以指向陣列的指標也複製了,指標指向原來切片指向的位置
之後隨著元素的加入會發生擴容,會將原來的陣列複製到一個新的陣列中,然後將原來的陣列的指標指向新的陣列,然後將原來的陣列的長度和容量都改為原來的兩倍。這個時候指標的位置發生變化
所以引數傳遞後能改變原來切片的元素,但是不能改變原來切片的長度和容量。引數傳遞擴容後不會改變原來切片的元素。 {: .prompt-tip }
下面是一個例子:


3、map
map是一個key-value的無序集合,主要是為了查詢方便,時間複雜度為O(1)
map中的key是唯一的,value可以重複
map中key的型別可以是bool、數字、string、指標、channel、還可以是隻包含前面幾個型別的介面、結構體、陣列,但是不能是slice、map、function,value可以是任意型別
3.1、map的基本用法
舉個例子:
var courseMap map[string]string{
"courseName": "golang",
"courseType": "backend",
}
// 其中基本格式是map[key_type] value_type
3.1.1、map的初始化
map型別想要使用必須先要初始化,不然map為nil(空指標),會報錯,不能使用
初始化的方式主要有兩種,一種是在定義的時候直接賦值,第二種是使用make函式進行初始化,分配空間,建立一個空的map
// 第一种初始化方式
var courseMap map[string]string{
"courseName": "golang",
"courseType": "backend",
}
// 第二种初始化方式
var courseMap = make(map[string] string, 10)//make是一个内置函数
coueseMap["courseName"] = "golang"
相比之下,slice可以不進行初始化
3.1.2、map獲取元素
map的獲取元素的方式是透過key來獲取value
如果key不存在,會返回value的零值
var courseMap map[string]string{
"courseName": "golang",
"courseType": "backend",
}
fmt.Println(courseMap["courseName"])
// 第二种获取元素的方式
value, ok := courseMap["courseName"]
if ok{
fmt.Println(value)
}else{
fmt.Println("key不存在")
}
if value, ok := courseMap["courseName"]; ok{
fmt.Println(value)
}else{
fmt.Println("key不存在")
}
3.1.3、map刪除元素
map有一個內建的delete函式,用來刪除map中的元素
如果刪除的元素不存在也不會報錯
delete(courseMap, "courseName")
//delete(map_name, key)
3.2、map的遍歷
map的遍歷是透過for-range的方式進行遍歷
map是無序的,所以遍歷的順序是不確定的,每次列印的順序可能不一樣
//第一种遍历方式,两个参数
for _, value := range courseMap{
fmt.Println(value)
}
// 第二种遍历方式,一个参数,key,然后通过key访问value
for key := range courseMap{
fmt.Println(key, courseMap[key])
}
4、list
4.1、list的基本介紹
list是一個”雙向連結串列”,是一個有序的集合,主要是為了插入和刪除方便,利用不連續空間
list佔用空間比較多,會額外儲存指標,指向前後的元素
列表插入和刪除比較方便,查詢比較麻煩,時間複雜度為O(n)
4.2、list的基本用法
var mylist list.List
mylist.PushBack("go")
mylist.PushBack("java")
mylist.PushBack("python")
// 遍历list(正向)
for i := mylist.Front(); i!= nil; i = i.Next(){
fmt.Println(i.Value)
}
// 反向遍历
for i:= mtlist.Back(); i != nil; i = i.Prev(){
fmt.Println(i.Value)
}
mylist.PushFront("c++")//头部插入元素
mylist.PushBack("c")//尾部插入元素
mylist.InsertAfter("c#", mylist.Front())//在指定元素后面插入元素
mylist.InsertBefore("c#", mylist.Back())//在指定元素前面插入元素
mylist.Remove(mylist.Front())//删除头部元素
mylist.Remove(mylist.Back())//删除尾部元素\
mylist.Remove(i))//删除指定元素