[原文链接](https://yc90s.github.io/2017/11/20/%E6%95%B0%E7%BB%84%E4%B8%8E%E5%88%87%E7%89%87/)
##数组
### 定义
数组是一组同类型数据的集合,它是**值类型**,通过从0开始的下标索引访问元素值。初始化后**数组长度是固定的**,无法修改其长度。当作为方法的入参传入时將复制一份数组而不是引用同一指针。数组的长度也是其类型的一部分。
### 初始化
- 长度为5的数组,其元素值依次为:1, 2, 3, 4, 5
```
[5]int{1, 2, 3, 4, 5}
```
- 长度为5的数组,其元素值依次为:1, 2, 0, 0, 0. 在初始化时没有指定初值的元素將会赋值为其元素类型的默认值,int是0,string是““
```
[5]int{1, 2}
```
- 长度为5的数组,其长度是根据初始化时指定的元素个数决定的
```
[...]int{1, 2, 3, 4, 5}
```
- 长度为5的数组,其元素值依次为:0, 0, 1, 2, 3. 在初始化时指定了2, 3, 4索引中对应的值:1, 2, 3
```
[5]int{2:1, 3:2, 4:3}
```
- 长度为5的数组,其元素值为:0, 0, 1, 0, 3. 由于指定了最大索引4对应的值为3, 根据初始化的元素个数确定其长度为5
```
[...]int{2:1, 4:3}
```
## 切片
### 定义
切片基于数组构建,但是提供更强的功能。切片的存储结构依次是底层数组的指针、切片长度、切片容量、切片数据。切片长度是指已经被赋过值的最大下标+1, 可通过len()获取。容量是指切片目前可容纳的最多元素个数,可通过cap()获取。**切片是引用类型**,而且**切片的长度和容量可以修改**,当切片的容量发生变化时,可能会重新分配内存,**使得切片和原底层数组的关联断开**
### 初始化
- 直接初始化,[]表示是切片类型,初始化值依次是1, 2, 3. 其cap=len=3
```
s := []int{1, 2, 3}
```
- 通过数组或其它切片初始化,是其的引用
```
s := arr[startIndex:endIndex]
```
- 通过make()初始化,可指定len和cap
```
s := make([]int, len, cap)
```
切片重新分配内存,导致切片和原底层数组关联断开的情况需要特殊注意,考虑如下代码:
```
arr1 := [3]int{1, 2, 3}
arr2 := [3]int{1, 2, 3}
sli1 := arr1[:1]
sli2 := arr2[:1]
sli1[0] = 0
sli2[0] = 0
sli1 = append(sli1, 5)
sli2 = append(sli2, 5, 5, 5)
fmt.Println("arr1: ", arr1)
fmt.Println("arr2: ", arr2)
fmt.Println("sli1: ", sli1)
fmt.Println("sli2: ", sli2)
```
执行后的输出结果是
> arr1: [0 5 3]
> arr2: [0 2 3]
> sli1: [0 5]
> sli2: [0 5 5 5]
对切片sli1的append操作实际并没有重新分配内存,它还是原数组的引用,所以对sli1的append操作仍而应用到了数组arr1上;而对切片sli2的append操作,重新分配了内存,使得它和原数组的关联断开了,所以对sli2的append操作并没有影响到数组arr2
## 数组与切片区别
### 数组长度不可变,切片长度和容量都可变
数组的长度在初始化时就会确定下来,而切片的长度可以动态变化
### 数组是值类型,而切片是引用类型
用一段代码说明一下
```
func testArr(arg [3]int) {
arg[0] = 0
fmt.Println("testArr: ", arg)
}
func testSli(arg []int) {
if len(arg) == 0 {
arg = append(arg, 0)
} else {
arg[0] = 0
}
fmt.Println("testSli: ", arg)
}
func main() {
arr := [3]int{1, 2, 3}
fmt.Println("before testArr(): ", arr)
testArr(arr)
fmt.Println("after testArr(): ", arr)
sli := arr[:]
fmt.Println("befor testSli(): ", sli)
testSli(sli)
fmt.Println("after testSli(): ", sli)
}
```
执行后程序输出
> before testArr(): [1 2 3]
> testArr: [0 2 3]
> after testArr(): [1 2 3]
> befor testSli(): [1 2 3]
> testSli: [0 2 3]
> after testSli(): [0 2 3]
testArr()函数对传进去的arr参数的修改,并没有对arr变量生效,而testSli()函数对sli变量的修改写回到了sli变量
有疑问加站长微信联系(非本文作者))