因为我是写php
的,刚开始写go
的时候老是被数组坑。因为在go
中的数组是固定长度,所以会存在越界的时候。而在go
中也很少直接使用数组。更多的时候会使用slice
(切片)。
数组
数组是一个由固定长度的特定类型元素组成的序列,一个数组可以由零个或多个元素组成。数组的长度是固定的。和数组对应的类型是Slice(切片),它是可以增长和收缩动态序列,slice功能也更灵活,但是要理解slice工作原理的话需要先理解数组。
数组的声明,需要指出数组内部元素类型,以及数组的长度
var name [len]type
如:声明一个长度为5的Int 类型数组
var numbers [5]int
数组元素的访问也是跟大多数语言一样,可以通过索引下标来访问,索引下标的范围是从0开始到数组长度减1的位置。内置的len函数将返回数组中元素的个数。
下面是一些数组的简单操作
func main() {
var arr [3]int //声明一个长度为3的数组
//往数组中增加元素
arr[0] = 1
arr[1] = 2
arr[2] = 3
// arr[3] = 1 这里就会产生错误
//在声明数组的时候复制
var addArr = [3]int{1, 2, 3}
fmt.Println(addArr[0]) //
moreArr := [...]int{1, 2} //这里...表示不确定长度。最终数组的长度由实际的元素个数确认
fmt.Println(moreArr[0]) //
//数组的使用
for k, v := range arr {
fmt.Printf("第%d个元素为%d\n", k+1, v)
}
}
切片
slice是一个轻量级的数据结构,提供了访问数组子序列(或者全部)元素的功能,slice的底层引用了一个数组对象。一个slice由三个部分构成:指针、长度和容量。指针指向第一个slice元素对应的底层数组元素的地址,要注意的是slice的第一个元素并不一定就是数组的第一个元素。长度对应slice中元素的数目;长度不能超过容量,容量一般是从slice的开始位置到底层数据的结尾位置。
func main() {
arr := [5]int{1, 2, 3, 4, 5} //定义一个数组
sle1 := arr[0:2] //切片1
sle2 := arr[1:3] //切片2
sle1[0] = 9 //现在改变第一个切片的第一个元素
fmt.Println(arr) //[9 2 3 4 5]
fmt.Println(sle1) //[9 2]
fmt.Println(sle2) //[2 3]
/**
* 现在改变两个切片共有的元素,通过结果可以看到
* 底层数组 以及sle2中的一个元素都以及被改变了。
* 可以很好的说明 切片是对数组的引用。两个切片实际引用的是同一个底层数组
*
*/
sle1[1] = 10
fmt.Println(arr) //[9 10 3 4 5]
fmt.Println(sle1) //[9 10]
fmt.Println(sle2) //[10 3]
}
上面的例子说明切片的第一个构成部分是指向底层数组的指针,下面来看看容量跟长度。
内置的len和cap函数分别返回slice的长度和容量。
func main() {
arr := [5]int{1, 2, 3, 4, 5}
sli := arr[:4] // [1,2]
fmt.Printf("切片长度为%d,容量为%d\n", len(sli), cap(sli))
//切片长度为4,容量为5
sl2 := arr[:2] // [1,2]
fmt.Printf("切片长度为%d,容量为%d\n", len(sl2), cap(sl2))
//切片长度为2,容量为5
sl3 := sli[:6] //这里会产生panic range of index。因为超过源切片的容量
}
这里我们可以看到,如果切片操作超出cap(s)的上限将导致一个panic异常,但是超出len(s)则是意味着扩展了slice,因为新slice的长度会变大。那么我们应该怎么去给切片扩容呢,这里我们需要用到append
方法、看下面的例子
func main() {
/**
* 这里使用make 创建一个切片
* make([]T, len, cap) 其中cap可以省略。默认为Len
*/
sli := make([]int, 1, 1)
fmt.Printf("切片长度为%d,容量为%d\n", len(sli), cap(sli)) //2
for i := 1; i < 5; i++ {
sli = append(sli, 2)
fmt.Printf("切片长度为%d,容量为%d\n", len(sli), cap(sli)) //2
}
}
输出结果
切片长度为1,容量为1,地址为0xc00005a420
切片长度为2,容量为2,地址为0xc00005a420
切片长度为3,容量为4,地址为0xc00005a420
切片长度为4,容量为4,地址为0xc00005a420
切片长度为5,容量为8,地址为0xc00005a420
通过上面例子可以看出,当切片长度大于当前容量的时候,会为当前切片自动扩容。每次扩容的大小为当前容量的2倍
数组跟切片的基本就到这了。还没有入门,学习中。有错误的地方欢迎指出。
有疑问加站长微信联系(非本文作者)