1、数组
数组长度定义后不可修改,通过内置函数len()来获取数组元素个数
1)类型
//长度为32的byte数组,每个元素为一个字节
[32]byte
//长度为2*N的复杂类型数组
[2*N] struct{x,y int32}
//长度100的指针数组
[100]*float64
//二维数组,等同于[2]([3]int)
[2][3]int
//三维数组
[2][2][2]float64
2)定义
//定义一个长度为5的数组,默认会使用int类型的零值(0)进行初始化
arr := [5]int{}
//与上面一句作用一样
var arr [5]int = [5]int{}
//定义一个长度为5的数组,其中arr[0]将被初始化为1,其余依旧是0
arr := [5]int{1}
//定义一个长度为5的数组,其中arr[0]、arr[4]将被初始化为1,其余依旧是0
arr := [5]int{0:1,4:1}
//定义一个长度为5的数组,默认会使用int类型的零值(0)进行初始化
arr := new([5]int)
//定义并初始化一个数组,这里会自动推断数组长度([...]起的作用),这里需要跟后面切片定义的不同(没有...)
arr := [...]int{1, 2, 3, 4, 5}
//定义并初始化一个数组,并且会自动推断长度为5,arr[4]将被初始化为1,其余依旧是0
arr := [...]int{4:5}
3)遍历
//与其它编程语言类型的遍历方式
//获取数组arr的长度
lenth := len(arr)
for i := 0; i < lenth; i++ {
//使用数组索引方式遍历数组
fmt.Print(arr[i], " ")
}
//使用range方式遍历数组,range有两个返回值,1为索引,2为值
for i, v := range arr {
fmt.Print("[",i,"]=",v, " ")
}
4)比较操作
在两个数据是同一类型(长度及元素类型)时,可以使用==与!=对两个数组进行比较,但不能使用<或>。
注:Go语言中数组是一个值类型,所有值类型变量在赋值和作为参数传递时都将产生一次复制动作,
传入函数中的数组仅是该数组的一个副本,因此就无法对其进行修改,如果此时的数组较大时,
将会降低程序的效率,关于这种场景的解决,下面的切片会进行讲解。
2、切片
在上面我们提到数组两个特点:
1、数据长度在定义后无法再次进行修改;
2、数据是值类型,每次传递都将产生一个副本;
而Slice(切片)正是为解决以上两个问题而存在。
从表象看,切片是一个指向原始数组的指针,但实际上,切片拥有自己的数据结构
1、一个指向原生数组的指针
2、数组切片中的元素个数
3、数组切片已分配的存储空间
这里需要区分两个概念,
长度:切片已使用的大小,从切片头开始算起,使用内置函数len()获取
容量:切片允许使用的大小,从切片头开始算起,至底层数组末尾,使用内置函数cap()获取,
当切片长度超过容量时,会重新分配一个原容量两倍的容间,并将值复制过去,与Java
中的ArrayList有点类似,要注意扩容后的内存地址与原内存地址不一样。
1)定义
//此处先定义一个数组
arr := [5]int{}
//基于上面定义的数据定义一个指向arr索引值在[0,5)范围(左开右闭)的切片
//这里的[m,n]还可以有多种写法,如[:5]表示[0,5),[1:]表示[1,len(arr)),[:]表示[0,len(arr))
arrSlice := arr[0:5]
//定义一个长度为5,容量也为5的切片,这里要注意跟上面数组定义的差别,数组定义时中括号中有...
arrSlice := []int{1,2,3,4,5}
//定义一个长度为5,容量也为5的切片
mySlice := make([]int,5)
//定义一个长度为5,容量为10的切片
mySlice := make([]int,5,10)
//在切片上再切片,这种情况又叫做reslice,这里的[m:n]必须满足0<=m
mySlice2 := mySlice[:]
在reslice的情况下,有很多地方需要注意,因为原slice与reslice实际底层使用的是同一块内存
空间,当两个的长度都在底层数组的长度内时,两者共享的都是同一块容间,当有一个超过之后,
这种情况将会被打破。如下面的代码所示:
mySlice := make([]int,5,6)
//即mySlice[1]对应mySlice2[1],以此类推
mySlice2 := mySlice[1:]
//这里相当于同时也对mySlice2[0]的值进行了修改
mySlice[1] = 10
//append为内置函数,表示给切片追加值,mySlice长度增加了,但mySlice2长度依旧不变
mySlice = append(mySlice,1)
//这里将会把mySlice[5]的值覆盖为2,即覆盖上一句代码的值
mySlice2 = append(mySlice2,2)
//经过上面代码,已经用完所有空间,再添加值时,将会发生空间分配
mySlice2 = append(mySlice2, 7)
//这里仅改变了mySlice2[0],而mySlice[1]不变
mySlice2[0] = -1
2)遍历与数组遍历一样,这里就不复述了
3)切片的增减
//在切片末尾添加值 1 ,如果超过容量,会导致重新分配容间,容量会是原容量的2倍
mySlice = append(mySlice,1)
//在切片末尾同是添加多个值
mySlice = append(mySlice,1,2,3)
//在切片末尾追加一个数组,这里的"..."是必需的,否则会编译错误,表示把数组打散后传入
mySlice = append(mySlice,arr...)
//在切片末尾添加另一个切片,这里mySlice2后的[:]被省略了
mySlice = append(mySlice,mySlice2...)
//切片的减,这里表示删除掉了mySlice[1],切片的长度减小,但容量不变
mySlice = append(mySlice[:1],mySlice[2:]...)
//切片的减,如果是要删除切片末尾的话,则可以使用reslice的方式为实现
mySlice = mySlice[0 : len(mySlice)-1]
4)内容复制
用于将内容从一个数组切片复制到另一个数组切片。
如果两个切片不一样大,将以较小切片的元素个数进行复制
//这里要注意顺序,与Java的那种前者from后者to相反
copy(targetSlice,sourceSlice)
3、map
未排序的键值对集合,系统直接内置,无需引入其它包
1)声明
var 变量名 map[键类型]值类型
var myMap map[int]string
2)创建
//创建一个key为int,值为string的map,myMap需要先声明
myMap = make(map[int]string)
//声明+创建
myMap := make(map[int]string)
//创建一个容量为100的map
myMap = make(map[int]string,100)
//声明+创建
myMap = map[int]string{}
//声明+创建+初始化
myMap = map[int]string{1: "1"}
3)元素赋值、删除、查找
//增加或修改key=123对应的元素值为字符型"123"
myMap[123] = "123"
//删除key=123对应的元素
delete(myMap,123)
//查找key=123对应的元素,该操作有两个返回值,多返回值知识点将在函数相关内容说到,
//返回值1为对应的值,返回值2为是否包含该key
v, ok := myMap[123]
本文介绍了编程中最常用的两种数据结构,数组及map,同时介绍了一种可伸缩的”数组”又可以看作为一个数组指针–切片,数组与切片有太多相似的地方,但同时又存在差异,所以做为新手要特别注意。
无闻(unknow)《Go编程基础》
许式伟的 《Go语言编程》