[TOC]
上一章讲的是 `array` 数组,实际使用频率不是很高。因为它是不能扩容的。定义的时候写3的值,就是固定三个值。所以才有本文介绍的 `slice` 切片类型。
切片(Slice)是一个拥有相同类型元素的可变长度的序列。它是基于数组类型做的一层封装。它非常灵活,支持自动扩容。
切片是一个引用类型,它的内部结构包含 `地址` 、 `长度` 和 `容量` 。
## 切片定义
```go
// (1) 定义并初始化
var s1 = []string{"jiaxzeng"}
fmt.Printf("s1: %v\n", s1)
// (2) 基于数组切片
var a1 = [5]int{1, 2, 3, 4, 5}
// 切片操作都是左闭右开 [)
// 从a1索引1开始切到2。
s2 := a1[1:3]
// 从a1索引0开始切到2,冒号前面空,则说明从开头开始
s3 := a1[:3]
// 从a1索引3开始切到结尾,冒号后面空,则说明切到最后。包含最后一个
s4 := a1[3:]
fmt.Printf("s2: %d, type: %T\n", s2, s2)
fmt.Printf("s3: %d, type: %T\n", s3, s3)
fmt.Printf("s4: %d, type: %T\n", s4, s4)
// 运行结果:
// s1: [jiaxzeng]
// s2: [2 3], type: []int
// s3: [1 2 3], type: []int
// s4: [4 5], type: []int
```
## make定义切片
如果需要动态的创建一个切片,我们就需要使用内置的make()函数
make函数定义切片语法:`make(Type, len, cap)`
```go
s5 := make([]int, 3, 5)
fmt.Printf("s5: %d, type: %T, len: %d, cap: %d\n", s5, s5, len(s5), cap(s5))
// 运行结果:
// s5: [0 0 0], type: []int, len: 3, cap: 5
```
## 切片的地址、长度和容量
可以通过使用内置的len()函数求长度,使用内置的cap()函数求切片的容量,使用 `fmt.Printf("%T", variable)` 打印地址
示例一:
```go
s6 := []string{"beijing", "guangdong", "shagnhai"}
for i := 0; i < len(s6); i++ {
fmt.Printf("s6[%d]: %s, pointer: %p\n", i, s6[i], &s6[i])
}
fmt.Printf("s6: %v, len: %d, cap: %d, pointer: %p\n", s6, len(s6), cap(s6), s6)
// 运行结果:
// s6[0]: beijing, pointer: 0xc000100150
// s6[1]: guangdong, pointer: 0xc000100160
// s6[2]: shagnhai, pointer: 0xc000100170
// s6: [beijing guangdong shagnhai], len: 3, cap: 3, pointer: 0xc000100150
```
示例二:
```go
var a2 = [5]int{1, 2, 3, 4, 5}
for i := 0; i < len(a2); i++ {
fmt.Printf("a2[%d]: %d, pointer: %p\n", i, a2[i], &a2[i])
}
s7 := a2[:3]
fmt.Printf("s7: %v, len: %d, cap: %d, pointer: %p\n", s7, len(s7), cap(s7), s7)
// 运行结果:
// a2[0]: 1, pointer: 0xc0000ba000
// a2[1]: 2, pointer: 0xc0000ba008
// a2[2]: 3, pointer: 0xc0000ba010
// a2[3]: 4, pointer: 0xc0000ba018
// a2[4]: 5, pointer: 0xc0000ba020
// s7: [1 2 3], len: 3, cap: 5, pointer: 0xc0000ba000
```
示例三:
```go
var a3 = [5]int{1, 2, 3, 4, 5}
for i := 0; i < len(a3); i++ {
fmt.Printf("a3[%d]: %d, pointer: %p\n", i, a3[i], &a3[i])
}
s8 := a3[2:4]
fmt.Printf("s8: %v, len: %d, cap: %d, pointer: %p\n", s8, len(s8), cap(s8), s8)
// 运行结果:
// a3[0]: 1, pointer: 0xc0000ba000
// a3[1]: 2, pointer: 0xc0000ba008
// a3[2]: 3, pointer: 0xc0000ba010
// a3[3]: 4, pointer: 0xc0000ba018
// a3[4]: 5, pointer: 0xc0000ba020
// s8: [3 4], len: 2, cap: 3, pointer: 0xc0000ba010
```
## 切片原理
切片是一个引用类型,本质就是对底层数组的封装。它的内部结构包含 `地址` 、 `长度` 和 `容量` 。
引用上面三种情况,相应示意图如下:
示例一:
![](https://img.kancloud.cn/94/28/942876d067c1aa93753358132c59b390_1017x447.png)
示例二:
![](https://img.kancloud.cn/b2/d0/b2d02f5c57e2bf70d7270c584262be6a_1334x402.png)
示例三:
![](https://img.kancloud.cn/a0/2c/a02c02a1f619a2a9f322205d3d0c2a4d_1336x411.png)
>[info] 总结:
> 1. 长度是 切片元素个数
> 2. 容量是 切片地址指向的底层数组下标到数组结尾
- Golang简介
- 开发环境
- Golang安装
- 编辑器及快捷键
- vscode插件
- 第一个程序
- 基础数据类型
- 变量及匿名变量
- 常量与iota
- 整型与浮点型
- 复数与布尔值
- 字符串
- 运算符
- 算术运算符
- 关系运算符
- 逻辑运算符
- 位运算符
- 赋值运算符
- 流程控制语句
- 获取用户输入
- if分支语句
- for循环语句
- switch语句
- break_continue_goto语法
- 高阶数据类型
- pointer指针
- array数组
- slice切片
- slice切片扩展
- map映射
- 函数
- 函数定义和调用
- 函数参数
- 函数返回值
- 作用域
- 函数形参传递
- 匿名函数
- 高阶函数
- 闭包
- defer语句
- 内置函数
- fmt
- strconv
- strings
- time
- os
- io
- 文件操作
- 编码
- 字符与字节
- 字符串
- 读写文件
- 结构体
- 类型别名和自定义类型
- 结构体声明
- 结构体实例化
- 模拟构造函数
- 方法接收器
- 匿名字段
- 嵌套与继承
- 序列化
- 接口
- 接口类型
- 值接收者和指针接收者
- 类型与接口对应关系
- 空接口
- 接口值
- 类型断言
- 并发编程
- 基本概念
- goroutine
- channel
- select
- 并发安全
- 练习题
- 第三方库
- Survey
- cobra