GO语言容器
数组
声明:
- var 数组名 [数组大小] T其中T可以为任意类型,也可以是数组本身,当类型为数组本身时,可以实现多维数组
初始化:
- var arr = [2]int{1,2} 或者 arr := [2]int{1,2}。 如果不确定数组的初始化长度也可以这样写 var arr = [...]int{1,2} 或者 arr := [...]int{1,2}
数组的遍历:
- 用for循环即可
arr := [...]int{1, 2, 3, 4, 5, 6}
for index,value:=range arr{
fmt.Println(index,value)
}
注意:
- 数组在go语言中是一个值类型,也就是说当我们进行数组赋值或者数组传参时,实际上都会拷贝一份新的数组。我们在拷贝数组上做任何改变都不会影响到原数组。
- 数组的类型也包括长度,通俗地说:两个int数组的长度不同,那么它们不是同一个类,数组的类型包括了数组的长度,这也是Go和其他语言不同的地方
二维数组
获取二维数组的行:len(nums) 获取二维数组的列:len(nums[0])
切片
Go语言切片的内部结构包含地址、大小和容量,是建立在数组类型之上的抽象,提供了更加强大的功能。底层是一个数组,切片是对数组连续片段的一个引用,所以切片是引用类型。
声明:
-
切片的声明和数组非常类似,但是它们是完全不同的,Go语言中的数组是基本类型,声明后就会开辟一块内存空间并初始化为零值,是可以直接使用的。而切片是一个引用类型,声明后并没有开辟内存空间,此时是nil(Java中的null),必须初始化之后才能使用才会分配给切片具体的内存空间。与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。
声明格式:
var identifier []type
//切片的声明并不会为其分配内存空间
var slice []int
var slice_empty []int
//切片初始化会为其分配相应的内存空间
var slice_int = []int{}
fmt.Println(slice,slice_empty,slice_int)
fmt.Println(slice_empty == slice_int)//报错:slice can only be compared to nil,意思为切片只能与nil做比较
make函数
我们还可以通过内建函数make()来直接获取切片,格式如下:make([]T, len, cap) T
- [ ]T:要创建的切片类型
- len:要创建的切片长度
- cap:要创建的切片容量 当我们使用make函数的时候我们一定为其进行了内存分配的操作
append函数
扩容机制:Go语言内建的append()方法可以为切片动态的添加元素。每个切片都会指向一块内存空间,这片空间能够容纳一定数量的元素(cap),当空间不够时,切片就会进行扩容。
func main() {
//切片的声明,并不会为其分配内存空间
var slice []int
for i := 0; i < 10;i ++{
slice = append(slice,i)
fmt.Printf("len: %d \t cap: %d pointer:%p \n",len(slice),cap(slice),slice)
}
fmt.Print(slice)
}
输出结果:
len: 1 cap: 1 pointer:0xc000018070
len: 2 cap: 2 pointer:0xc000018090
len: 3 cap: 4 pointer:0xc00001a040
len: 4 cap: 4 pointer:0xc00001a040
len: 5 cap: 8 pointer:0xc00001e100
len: 6 cap: 8 pointer:0xc00001e100
len: 7 cap: 8 pointer:0xc00001e100
len: 8 cap: 8 pointer:0xc00001e100
len: 9 cap: 16 pointer:0xc000014080
len: 10 cap: 16 pointer:0xc000014080
[0 1 2 3 4 5 6 7 8 9]
- 可以看出每次切片在容量不足时都会扩容,而扩容的容量是原来的两倍
- 每次扩容完之后切片的内存地址就会改变,本质上就是在内存中开辟了一块新的连续内存空间,将旧的切片拷贝到新的内存空间中
copy函数
我们使用Go语言的内建函数copy()时,可以进行切片的复制,使用格式如下
copy(des []T,src []T) int
返回实际拷贝的元素数量
我们在使用copy函数的时候要注意:两个切片的类型必须一致,否则会出现错误。当des切片的长度(len)小于src的长度(len)时(是长度而不是容量),只会拷贝des能接收的最大数量的元素。
func main() {
//切片的声明,并不会为其分配内存空间
var slice []int
for i := 0; i < 10;i ++{
slice = append(slice,i)
fmt.Printf("len: %d \t cap: %d pointer:%p \n",len(slice),cap(slice),slice)
}
fmt.Print(slice)
//make(切片类型,切片长度,切片容量)
var copySlice = make([]int,4,5)
//当des切片的长度(len)小于src的长度(len)时(是长度而不是容量),只会拷贝des能接收的最大数量的元素。
copy(copySlice,slice)
fmt.Println(copySlice)
}
--------
output:
[0 1 2 3 4 5 6 7 8 9][0 1 2 3]
切片中元素的删除
切片中并没有直接删除元素的方法,所以我们需要利用切片的特性来删除特定位置的元素。
//切片删除
seq := []int{1, 2, 3, 4, 5, 6, 7, 8}
//删除位置
index := 3
//通过append()函数来删除
seq = append(seq[:index], seq[index+1:]...)
fmt.Println(seq)
...语法糖在golang中的用法
1: 用于接受函数多个不确定参数
2: 将切片打散传递
-例如 seq = append(seq[:index], seq[index+1:]...) ,就是将index+1之后的元素打散一个个拼接到seq[:index]之后
Map
声明:
var name map[KeyType]ValueType这样声明之后map仅仅是一个指针,并没有为其分配对应的内存空间,只有在初始化map的时候才会分配内存空间。
初始化操作:
-
使用make函数初始化:
var m1 map[int]string m1 = make(map[int]string) -
声明时初始化:
m2 := map[int]string{ 1:"11", 2:"22", }
map的遍历
m2 := map[int]string{
1:"11",
2:"22",
}
//key和value一起打印
for key,value := range m2{
fmt.Printf("key:%d value:%s \n",key,value)
}
//单独打印key
for key := range m2{
fmt.Printf("key:%d \n", key)
}
//单独打印value
for _,value := range m2{
fmt.Printf("value:%s \n", value)
}
-------
output:
key:1 value:11
key:2 value:22
key:1
key:2
value:11
value:22
delete函数
我们可以使用Go的内建函数delete()来删除map中的键值对,delete格式如下
delete(map,key)
该方法没有返回值
delete()函数只能删除指定的一个键值对,如果我们要清空map中的元素,唯一的方法就是重新make一个新的map
list
初始化:
- 通过 container/list 包的 New() 函数初始化 list :
变量名 := list.New() - 通过 var 关键字声明初始化 list :
var 变量名 list.List
插入元素
| 方法 | 功能 |
|---|---|
| func (l *List) PushFront(v interface{}) *Element | 向列表头部添加元素,返回添加节点的指针 |
| func (l *List) PushBack(v interface{}) *Element | 向列表尾部添加元素,返回添加节点的指针 |
| func (l *List) InsertAfter(v interface{}, mark *Element) *Element | 在给定节点之后插入元素,返回插入节点的指针 |
| func (l *List) InsertBefore(v interface{}, mark *Element) *Element | 在给定节点之前插入元素,返回插入节点的指针 |
| func (l *List) PushBackList(other *List) | 将other列表添加到当前列表尾部 |
| func (l *List) PushFrontList(other *List) | 将other列表添加到当前列表头部 |
例如:
listTest := list.New()
listTest.PushFront("123") //将字符串123插入列表头部
listTest.PushFront(123) //将数值123插入列表头部,列表为:123 -〉 “123”
删除元素
1. package main
2.
3. import "container/list"
4.
5. func main() {
6. l := list.New()
7.
8. // 尾部添加
9. l.PushBack("canon")
10.
11. // 头部添加
12. l.PushFront(67)
13.
14. // 尾部添加后保存元素句柄
15. element := l.PushBack("fist")
16.
17. // 在fist之后添加high
18. l.InsertAfter("high", element)
19.
20. // 在fist之前添加noon
21. l.InsertBefore("noon", element)
22.
23. // 使用
24. l.Remove(element)
25. }
代码说明如下:
第 6 行,创建列表实例。
第 9 行,将字符串 canon 插入到列表的尾部。
第 12 行,将数值 67 添加到列表的头部。
第 15 行,将字符串 fist 插入到列表的尾部,并将这个元素的内部结构保存到 element 变量中。
第 18 行,使用 element 变量,在 element 的位置后面插入 high 字符串。
第 21 行,使用 element 变量,在 element 的位置前面插入 noon 字符串。
第 24 行,移除 element 变量对应的元素。
遍历列表
遍历双链表需要配合 Front() 函数获取头元素,遍历时只要元素不为空就可以继续进行,每一次遍历都会调用元素的 Next() 函数,代码如下所示。
1. l := list.New()
2.
3. // 尾部添加
4. l.PushBack("canon")
5.
6. // 头部添加
7. l.PushFront(67)
8.
9. for i := l.Front(); i != nil; i = i.Next() {
10. fmt.Println(i.Value)
11. }
------
output:
67
canon
代码说明如下:
- 第 1 行,创建一个列表实例。
- 第 4 行,将 canon 放入列表尾部。
- 第 7 行,在队列头部放入 67。
- 第 9 行,使用 for 语句进行遍历,其中 i:=l.Front() 表示初始赋值,只会在一开始执行一次,每次循环会进行一次 i != nil 语句判断,如果返回 false,表示退出循环,反之则会执行 i = i.Next()。
- 第 10 行,使用遍历返回的 *list.Element 的 Value 成员取得放入列表时的原值。