了解Go语言的切片(Slice)之前,我们先了解下Go语言的数组。
数组是一个线性数据结构,具有相同唯一类型的一组已编号且长度固定的数据项序列,数组的存储类型可以是任意类型。
1、声明一个int类型的数组:
var myArr [10]int;
2、初始化数组:
myArr=[10]int{1,2,3,4,5};
使用fmt.Println(myArr)输出结果为:[1 2 3 4 5 0 0 0 0 0]。
3、数组的长度
使用fmt.Println(len(myArr))输出结果为:10。
以上数组的操作和其他语言如Java、.net类似,也体现了数组的基本特征。
下面我们使用数组进行参数的传递。
func modifyArray(arr [10]int){
for index:=0;index<len(arr);index++{
arr[index]+=1;
}
}
fmt.Println(myArr);
输出结果为:[1 2 3 4 5 0 0 0 0 0]
数组的值没有发生变化,这一点说明Go语言的数字是按照值类型传递参数的。
注意上述的改变数组的方法参数是带有数字的,为什么要这样我们等会再阐述。
现在我们使用指针作为形参来进行数组的传值,方法改为:
func modifyArray(arr *[10]int){
for index:=0;index<len(arr);index++{
arr[index]+=1;
}
}
执行该函数并输出数组:
modifyArray(&myArr);//注意这里传递的是数组的地址
fmt.Println(myArr);
输出结果为:[2 3 4 5 6 1 1 1 1 1]
数组的值修改成功。
以上实例说明,数字的声明和初始化是需要指定个数的,包括数组作为参数进行传递的时候也是需要指定个数,否则会报错。
再强调一遍:数字的声明和初始化是需要指定个数。
如果我们不想指定个数呢,每次都指定个数很麻烦的好不好,那我们就指定个数试一试,程序员就要任性。
重新定义变量myArr:
Var myArr=[]int{1,2,3,4,5,0,0,0,0,0};
fmt.Println(myArr);
输出结果为:[1 2 3 4 5 0 0 0 0 0]
答案是可以的。
下面重新进行参数的传递。
func modifyArray(arr []int){ //注意[]int没有指定个数
for index:=0;index<len(arr);index++{
arr[index]+=1;
}
}
fmt.Println(myArr);
输出结果为:[2 3 4 5 6 1 1 1 1 1]
MyArr的值已经被修改了,这是什么情况?
我们回想一下刚才对数组强调的一句话:数字的声明和初始化是需要指定个数。如果不指定个数,那就不是数组,而是切片(Slice)。
使用var myArr=[]int{1,2,3,4,5,0,0,0,0,0};实际上是定一个一个切片。切片在参数传递的使用是传递的引用。
那么,到底什么是切片呢?切片是一个数据类型还是一个方法?
切片我们可以理解为“动态数组”,切片内部封装了一个数组指针,并能够通过切片实现数组的“动态”效果。
Slice的数据机构如下:
type slice struct {
array unsafe.Pointer //指向数组的指针
len int //切片长度
cap int //切片容量
}
Slice不是一个数组,而是一个特殊的结构体,当我们创建一个切片的使用,相当于创建了一个数组,该数组的指针就保存在切片内,任何对指针的操作都会反映到数组上,所以抛开这点,切片和数组的操作是一样的。
除了刚才的方式定义切片,我们也可以使用如下方式定义:
var sliceArr []int = make([]int, 10)
fmt.Println(slice1);
输出结果为:[0 0 0 0 0 0 0 0 0 0]
我们也可以通过截取数组的方式创建切片:
var myArr [10]int;
myArr=[10]int{1,2,3,4,5,0,0,0,0,0};
s := myArr[0:5];//从0开始,长度为5的元素到切片,这时候切片的数值指针指向Arr[0:5]
fmt.Println(s);
输出结果为:[1,2,3,4,5]
modifyArray(s);//切片元素值++
fmt.Println(s);
fmt.Println(myArr);
输出结果为:[2 3 4 5 6]
[2 3 4 5 6 0 0 0 0 0]
这时候除了切片的元素值变化,数组Arr的值也发生了变化。
Go语言切片的append
s:=[]int{1,2,3,4,5}
fmt.Println(s);
fmt.Println(&s[0]);
s=append(s,6);
fmt.Println(s);
fmt.Println(&s[0]);
输出结果:
[1 2 3 4 5]
0xc042072090
[1 2 3 4 5 6]
0xc042086000
数组首个元素的指针地址发生了变化,说明append在扩充时,只要超过了原有数组的上限,就会自动创建一份拷贝。
理解了以上,我们差不多也就对Go的数组和切片有个大致的了解,只要多加练习,就能够熟练掌握这些知识点。