Golang中array和slice的区别

The difference between array and slice in golang

Posted by alovn on January 18, 2020

先搞清楚Array和Slice的定义,Array 简单数组:是一组同类型元素的序列,序列长度也是数组定义的一部分。语法为:

1
Array := [ArrayLength] ElementType

不同长度的数组代表不同的数据类型:

1
2
3
4
5
6
7
arr1:=[3]string{}
arr2:=[6]string{}
fmt.Printf("type of arr1 is %s, the kind is %s\n",reflect.TypeOf(arr1),reflect.TypeOf(arr1).Kind())
fmt.Printf("type of arr2 is %s, the kind is %s\n",reflect.TypeOf(arr2),reflect.TypeOf(arr2).Kind()) 
//output
//type of arr1 is [3]string, the kind is array
//type of arr2 is [6]string, the kind is array

同时,Array在定义时,便给内部元素赋值为类型默认值。

1
arr :=[4]int

arr内存已经包含四个元素,其默认值为0。 当在定义Array时,如果无法确定长度,则可以使用”…“,来由实际元素个数确定数组长度:

1
b := [...]string{"Penn", "Teller"}

此时,数组b则由编译器检查其元素个数,确认其长度为2。

1
b := [2]string{"Penn", "Teller"}

实际两者等价。

Array一个重要的特性是:长度不可变。

那么如何满足可变长度的操作呢?最简单方式便使用Slice

Slice切片:一种提供丰富操作功能的元素序列,是对简单数组的高级抽象,是简单数组的强化版。实际切片内部也是对简单数据的引用,再提供高效的方式操作数组。其语法定义是:

1
SliceT := []ElementType

是不需要特别指定长度的,内部将包含容量、元素长度信息。

Array和Slice两者的差异

两者最大的差异是数组长度一旦确定便不可修改,无法变长,无法改短。而切片则通过伸缩容量。且数组是值类型,把一个数组赋予给另一个数组时是发生值拷贝,而切片是指针类型,拷贝的是指针。

下面通过一个实例来说明:代码如下: (1)是定义一个[3]int类型数组,依次赋值为1,2,3。 (2)将数组a赋值给b,将发生值拷贝。 (3)给数组a的下标2的元素赋值为4,这并不会影响数组b的内容。 (4)打印结果,得以说明情况。

1
2
3
4
5
6
7
8
9
10
11
//array
a:=[3]int{1,2,3}
b:=a
a[2]=4
fmt.Println("a = ", a)
fmt.Println("b = ", b)
fmt.Println(reflect.TypeOf(a).Kind())
// Output
// a = [1, 2, 4]
// b = [1, 2, 3]
// array

再看另一段代码:(1)不指定长度,(2)打印结果,显示有对a的修改影响了b的内容。

1
2
3
4
5
6
7
8
9
10
11
//slice
a:=[]int{1,2,3}
b:=a
a[2]=4
fmt.Println("a = ", a)
fmt.Println("b = ", b)
fmt.Println(reflect.TypeOf(a).Kind())
// Output
// a = [1, 2, 4]
// b = [1, 2, 4]
// slice

为何一个细微的变化有如此差异呢?这个便是Array和Slice定义时语法上的细微差异:

在括号中定义一个长度值,是编译器区别变量a数据类型的唯一依据,带长度值便是数组,不带便是切片。

可以通过 reflect.TypeOf(a).Kind() 判断是数组还是切片。

而且切片是引用传递,Array是值传递。

[] 是 slice,[n] 和 […] 都是 array。

Golang 绝大部分还是用到的是slice,普通程序里绝少有用到 Array 的地方。