## 一、切片定义
Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go 中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。
#### 1、语法:
~~~
var identifier []type
~~~
注:切片不需要说明长度。
#### 2、使用**make()**函数来创建切片:
~~~
var slice1 []type = make([]type, len)
也可以简写为
slice1 := make([]type, len)
~~~
#### 3、也可以指定容量,其中**capacity**为可选参数。
~~~
make([]T, length, capacity)
~~~
注:这里 len 是数组的长度并且也是切片的初始长度。
#### 4、切片的类型
切片(slice)是对数组一个连续片段的引用,所以切片是一个引用类型。
#### 5、切片的结构
切片有3个字段的数据结构:一个是指向底层数组的指针,一个是切片的长度,一个是切片的容量。
#### 切片实例
~~~
package main
import "fmt"
func main() {
//初始化切片
a1 := make([]int, 3)
a1[0] = 1
a1[1] = 2
a1[2] = 3
fmt.Println("a1的值为", a1)
a2 := []int{1, 2, 3}
fmt.Println("a2的值为", a2)
}
~~~
执行结果:
a1的值为 [1 2 3]
a2的值为 [1 2 3]
## 二、 len() 和 cap() 函数
切片是可索引的,并且可以由 len() 方法获取长度。
切片提供了计算容量的方法 cap() 可以测量切片最长可以达到多少。
~~~
package main
import "fmt"
func printSlice(x []int) {
fmt.Printf("len=%d cap=%d slice=%v\n", len(x), cap(x), x)
}
func main() {
//初始化切片
a1 := make([]int, 3)
a1 = append(a1, 1)
fmt.Println("a1的值为", a1)
printSlice(a1)
}
~~~
执行结果:
a1的值为 [0 0 0 1]
len=4 cap=6 slice=[0 0 0 1]
## 三、空(nil)切片
~~~
package main
import "fmt"
func main() {
var numbers []int
printSlice(numbers)
if numbers == nil {
fmt.Printf("切片是空的")
}
}
func printSlice(x []int) {
fmt.Printf("len=%d cap=%d slice=%v\n", len(x), cap(x), x)
}
~~~
执行结果:
len=0 cap=0 slice=[]
切片是空的
## 四、切片截取
~~~
package main
import "fmt"
func main() {
/* 创建切片 */
numbers := []int{0, 1, 2, 3, 4, 5, 6, 7, 8}
/*
len=9 cap=9 slice=[0 1 2 3 4 5 6 7 8]
*/
printSlice(numbers)
/* 打印原始切片 */
//[0 1 2 3 4 5 6 7 8]
fmt.Println("numbers ==", numbers)
/* 打印子切片从索引1(包含) 到索引4(不包含)*/
//[1 2 3]
fmt.Println("numbers[1:4] ==", numbers[1:4])
/* 默认下限为 0*/
//[0 1 2]
fmt.Println("numbers[:3] ==", numbers[:3])
/* 默认上限为 len(s)*/
//[4 5 6 7 8]
fmt.Println("numbers[4:] ==", numbers[4:])
numbers1 := make([]int, 0, 5)
//len=0 cap=5 slice=[]
printSlice(numbers1)
/* 打印子切片从索引 0(包含) 到索引 2(不包含) */
number2 := numbers[:2]
//len=2 cap=9 slice=[0 1]
printSlice(number2)
}
func printSlice(x []int) {
fmt.Printf("len=%d cap=%d slice=%v\n", len(x), cap(x), x)
}
~~~
运行结果:
len=9 cap=9 slice=[0 1 2 3 4 5 6 7 8]
numbers == [0 1 2 3 4 5 6 7 8]
numbers[1:4] == [1 2 3]
numbers[:3] == [0 1 2]
numbers[4:] == [4 5 6 7 8]
len=0 cap=5 slice=[]
len=2 cap=9 slice=[0 1]
## 五、append() 和 copy() 函数
如果想增加切片的容量,我们必须创建一个新的更大的切片并把原分片的内容都拷贝过来。
下面的代码描述了从拷贝切片的 copy 方法和向切片追加新元素的 append 方法。
~~~
package main
import "fmt"
func main() {
var numbers []int
printSlice(numbers)
/* 允许追加空切片 */
numbers = append(numbers, 0)
printSlice(numbers)
/* 向切片添加一个元素 */
numbers = append(numbers, 1)
printSlice(numbers)
/* 同时添加多个元素 */
numbers = append(numbers, 2, 3, 4)
printSlice(numbers)
/* 创建切片 numbers1 是之前切片的两倍容量*/
numbers1 := make([]int, len(numbers), (cap(numbers))*2)
/* 拷贝 numbers 的内容到 numbers1 */
copy(numbers1, numbers)
printSlice(numbers1)
}
func printSlice(x []int) {
fmt.Printf("list=%v\n", x)
}
~~~
执行结果:
list=[]
list=[0]
list=[0 1]
list=[0 1 2 3 4]
list=[0 1 2 3 4]
## 六、切片的定义
方式一:通过make内置函数来创建切片。基本语法: var切片名\[type = make(\[\], len,\[cap\])
![](https://img.kancloud.cn/98/82/9882406ed892300195da60f7f1775301_689x284.png)
方式二:定一个切片,直接就指定具体数组,使用原理类似make的方式。
![](https://img.kancloud.cn/03/01/0301960481739079340a43fd7e2ffc3d_689x116.png)
## 七、切片的遍历
```
package main
import "fmt"
func main(){
//定义切片:
slice := make(\[\]int,4,20)
slice\[0\] = 66
slice\[1\] = 88
slice\[2\] = 99
slice\[3\] = 100
//方式1:普通for循环
for i := 0;i < len(slice);i++ {
fmt.Printf("slice\[%v\] = %v \\t" ,i,slice\[i\])
}
fmt.Println("\\n------------------------------")
//方式2:for-range循环:
for i,v := range slice {
fmt.Printf("下标:%v ,元素:%v\\n" ,i,v)
}
}
```
## 八、扩容机制
![](https://img.kancloud.cn/35/95/359543465a85b26b6371b7b96d020cb9_689x541.png)
## 九、slice为什么不是线程安全
![](https://img.kancloud.cn/47/a4/47a40837507916697cb641378f7d6a1b_689x456.png)