文章15 | 阅读 7601 | 点赞0
前面的文章介绍了Go的一些基本类型,本文开始涉及Go的一些容器类型,它们都是可以包含多个元素的数据结构,如数组、切片、map
数组是具有相同类型且长度固定的一组元素集合,定义的格式:var 数组名 [数组长度]数组元素类型
,下面声明一个长度为5的int型数组arr
var arr [5]int
len(arr)
var arr = [5]int{1, 2, 3, 4, 5}
a := [3]int{1, 2, 3}
还可以在初始化时仅初始化指定元素
b := [3]int{1 : 2, 2 : 3} //初始化索引为1的值为2,索引为2的值为3
...
代替,编译器会自动生成满足最低长度要求的数组c := [...]int{4 : 1} //因为我们指定了索引为4的值为1,因此数值至少包含5个元素,这里将生成长度为5的数组
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)
}
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)是对某个数组的一段连续片段的引用(该数组我们称为相关数组,该片段可以是整个数组,也可以是数组中的某一段),因此切片是一个引用类型。切片底层实现是数组,它与数组的关系如下图:
多个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)
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(被追加元素的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的容量,则返回原始的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是Go里面的键值对集合,由key-value对组成,给定key,可以快速定位到对应的value。也被称为字典、哈希表等
==
或者!=
操作符比较的类型,比如string
,int
、float
等,不能是函数、map、切片;value可以是任意类型var map变量名 map[key类型]vlaue类型
var m map[int]string //声明
m = map[int]string{1:"a", 2:"b"} //初始化
特别注意,map必须要初始化才能使用,即如果用上面这种方式,必须要有初始化的语句map1 = map[keyType]ValueType{}
,否则将报错。当然如果觉得太繁杂,可以使用下面的make
语句来替代,更加简洁(主要是因为使用前需要先分配好内存空间给map,使用初始化语句或者make
语句才能实现空间的分配)
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
为容量,可以省略。超出容量会自动扩容,但为了性能还是尽量提供一个大概的初始值。
a:=m[1]
(获取key为1的value)m[1]="ok"
map[key]
还有另外一种用法:value,isPresent = map[key]
,即返回两个值,第二个值isPresent
是布尔类型,如果该key存在,该值为true
,且value
为该key对应的值;如果key不存在,则isPresent
为false
,且value
为空值。if value, ok := map1[key1];ok{
fmt.Println(value)
}
delete(map1, key1)
for-range
对map进行遍历map1 := make(map[int]string)
map1[1] = "a"
map1[2] = "b"
map1[3] = "c"
for key, value := range map1 {
fmt.Println(key,value)
}
如果指向获取key或者value,可以这么使用
for key := range map1 {
fmt.Println(key)
}
for _, vlaue := range map1 {
fmt.Println(value)
}
需要注意的是,for
中获得的key和value值都是副本,直接对这两个值进行修改并不会对原来的map有影响。需要用map[key]
才能真正改变map中的值
make
,第一次分配切片,第二次分配切片中每个map元素sm := make([]map[int]string, 5)
for i := range sm {
sm[i] = make(map[int]string,1)
sm[i][1]="ok"
}
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"
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/xah100147/article/details/106139589
内容来源于网络,如有侵权,请联系作者删除!