Go的切片类型为处理同类型数据序列提供一个方便而高效的方式。 切片有些类似于其他语言中的数组,但是有一些不同寻常的特性。 本文将深入切片的本质,并讲解它的用法。
数组
Go语言的切片是构建在数组之上的概念,我们在理解切片之前要先知道什么是数组.
与C语言基本相同,Go中的数组在定义时已经规定好了其长度,并且可以以[]这样的索引来进行访问,从0开始计数
不过不同的地方在于,Go中的数组是值语义,一个变量表示的就是整个数组而不是像C中表示数组的头一个元素的指针,当我们对数组类型进行传递的时候,传递的不是地址而是整个数组.[4]int与[5]int并不是同一个类型的数组,他们无法相互转换.
下面来看一下数组的基本用法
//这样会创建一个数组
//数组类型长度和容量是对等的,并且是在定义时就已经确定好了.无法变化
//数组的访问方式跟c一样
var a [4]int
a[0] = 5
b := [2]string{"Penn", "Teller"}
b[0] = "Go"
//b[2] = "Go" 这样会出错,因为超过了数组的容量
切片
在Go语言中,切片是我们会用的最多的类数组的数据结构,他与数组的访问方法基本相同,但是其底层的数据结构不大一样.数组是固定长度的,而切片是固定容量,长度可变的,他有两个属性值,一个叫做capacity,也就是容量,一个切片被创建时,容量也就确定了,一个叫做length,length是随着切片中元素的个数不同而动态变化的.
切片的生成
在Go语言中,主要使用内置函数make来进行创建一个切片.
//创建一个长度和容量都是5的切片,第一个参数指定类型,第二个参数指定长度
a := make([]byte,5)
len(a)//5
cap(a)//5
//创建一个长度为5,容量为10的切片,第一个参数指定类型,第二个参数指定长度,第三个参数指定容量
b := make([]byte,5,10)
len(b)//5
cap(b)//10
第一个创建的切片如下所示,第一个格子存储数据,第二个存储长度,第三个存储容量.

第二个创建的切片如下所示

切片的引用
如果学过Python的同学,应该会对这种引用方式十分熟悉.我们通过以下方式来进行切片的引用
letter := []string{"a","b","c","d","e"}
letter2 := letter[1:4]
//letter2 [b c d]
letter3 := letter[1:]
//letter3 [b c d e]
letter4 := letter[:3]
//letter4 [a b c]
如上所示,我们可以用:在[]里面进行切分,其数值遵循左闭右开原则,如果不指定值,则左值默认为0,右值默认为切片的长度(length),不过不同的是,我们无法通过指定一个负数来访问后面的元素,也不能引用超过长度的元素.
切片的增加
我们之前说到过,切片和数组的不同在于长度可变,虽然容量在创建时已经固定,但是我们可以通过内置函数append来对切片进行动态扩容以及元素的加入.我们也可以使用copy函数来进行扩容
//增加容量的方法1,创建一个新的切片,将容量设置得大一些
//然后复制源数组,并将新的数组的引用转到源数组
t:= make([]string, len(letter),((cap(letter)+1)*2))
copy(t,letter)
letter = t;
//增加容量的方法2,append方法
//这是一个内置的方法,对切片进行动态扩容
//我们只需要指定好增加的元素即可,因为其内部会动态扩容
// num = [0 1 2 3 4 5 6]
num := make([]int,1,1)
num = append(num,1,2,3,4,5,6)
// 可以这样来复制一个切片
// num2 = [0 0 1 2 3 4 5 6]
num2 := make([]int,0)
num2 = append(num2,num...)
//用这种方式来遍历切片
for i , v := range num2 {
num2[i] = v
}
fmt.Println(num2)
// 对于数组来说,不能像切片一样被很方便地拓展
// 所以需要通过一个显式的循环来进行复制
// num3 = [Go Teller]
num3 := make([]string,0)
for _,v := range b {
num3 = append(num3,v)
}
fmt.Println(num3)