切片(Slice)是一个拥有相同类型元素的可变长度的序列。它的本质是对数组的封装。它支持自动扩容。切片是一个引用类型,它的内部结构包含地址、长度和容量。切片一般用于快速地操作一块数据集合。
切片的本质就是对底层数组的分装,其包含了三个信息:底层指向数组的指针,切片的长度(len)和切片的容量(cap)
//声明切片的基本语法如下:
var name []T //name表示变量名,T表示切片中元素的类型
package main
import "fmt"
func main(){
var sli []string //声明一个字符串切片
var sli1 = []int{1, 2, 3} //声明一个整型切片并初始化
var sli2 = []bool{false, true} //声明一个布尔型切片并初始化
//使用make函数构造切片,参数分别为切片的类型,长度,容量
sli3 := make([]int, 5, 10)
fmt.Println(sli) //[]
fmt.Println(sli1) //[1 2 3]
fmt.Println(sli2) //[false true]
fmt.Println(len(sli1)) //默认的长度是3
fmt.Println(cap(sli1)) //默认容量也是3
fmt.Println(len(sli1)) //通过len函数可以获取切片的长度
fmt.Println(cap(sli1)) //通过cap函数可以获取切片的容量
fmt.Println(len(sli2)) //2
fmt.Println(cap(sli2)) //2
fmt.Println(sli3) //[0 0 0 0 0]
fmt.Println(len(sli3)) //5
fmt.Println(cap(sli3)) //10
}
切片的底层就是一个数组,所以我们可以基于数组通过切片表达式得到切片。 切片表达式中的low和high表示一个索引范围(左包含,又不包含),也就是下面代码中从数组arr中选出1<=索引值<4的元素组成切片sli,得到的切片长度=high-low,容量等于得到的切片的底层数组的容量。
package main
import "fmt"
func main(){
arr := [5]int {1, 2, 3, 4, 5}
var sli []int = arr[1 : 3]
fmt.Println(len(sli)) //2
fmt.Println(cap(sli)) //4
fmt.Println(sli) //[2 3]
}
简单切片表达式:为了方便起见,可以省略切片表达式中的任何索引。省略了low则默认为0;省略了high,则默认为切片操作数的长度:
package main
import "fmt"
func main(){
arr := []int{1, 2, 3, 4, 5}
sli := arr[2:] // 等同于 a[2:len(a)]
sli := arr[:3] // 等同于 a[0:3]
sli := arr[:] // 等同于 a[0:len(a)]
}
注意事项:
- 对于数组或字符串,若0 <= low <= high <= len(a),则索引合法,否则就会索引越界(out of range)。
- 对于切片再执行切片表达式时(切片再切片),high的上限边界是切片的容量cap(a),而不是长度。常量索引必须是非负的,并且可以用int类型的值表示;
- 对于数组或常量字符串,常量索引也必须在有效范围内。如果low和high两个指标都是常数,它们必须满足low <= high。如果索引在运行时超出范围,就会发生运行时panic。
package main
import "fmt"
func main(){
arr := [...]int{1, 2, 3, 4, 5}
sli := arr[1:3] //sli := arr[low, high]
fmt.Printf("%v %v %v\n", sli, len(sli), cap(sli))
sli2 := s[3:4] // 索引的上限是cap(s)而不是len(s)
fmt.Printf("%v %v %v\n", sli2, len(sli2), cap(sli2))
}
完全切片表达式:对于数组,指向数组的指针,或切片a(注意不能是字符串)支持完整切片表达式:
arr[low : high : max]
上面的代码会构造与简单切片表达式arr[low: high]相同类型、相同长度和元素的切片。切片的容量设置为max-low。在完整切片表达式中只有第一个索引值(low)可以省略;它默认为0。
package main
import "fmt"
func main() {
arr := [...]int{1, 2, 3, 4, 5}
sli := arr[1 : 3 : 5]
fmt.Printf("%v %v %v\n", sli, len(sli), cap(sli))
}
切片的遍历方式和数组是一样的,也支持索引遍历和for range遍历。
package main
import "fmt"
func main(){
arr := []int{1, 2, 3}
for i := 0; i < len(arr); i++ {
fmt.Println(arr[i])
}
for _, value := range arr {
fmt.Println(value)
}
}
- Go语言的内建函数append()可以为切片动态添加元素。 可以一次添加一个元素或者多个元素,也可以添加另一个切片中的元素(后面加…)。
package main
import "fmt"
func main(){
var sli1 []int
sli1 = append(sli1, 1, 2, 3) //向切片sli中添加元素
sli2 := []int {4, 5, 6}
sli1 = append(sli1, sli2...) //向切片sli1中添加其他切片的元素
fmt.Println(sli1)
}
- Go语言中并没有删除切片元素的专用方法,但可以借助切片本身的特性来删除, 操作方法如下:sli = append(sli[:index], sli[index + 1 :]…)
package main
import "fmt"
func main(){
//从切片中删除元素
sli := []int{1, 2, 3, 4, 5, 6, 7}
fmt.Println(sli)
//删除索引为5的元素
sli = append(sli[:5], sli[6:]...)
fmt.Println(sli)
}
- Go语言中内建的copy()函数可以将一个切片的数据复制到另外一个切片的空间中,copy()函数的使用格式如下:copy(destSlice, srcSlice)
package main
import "fmt"
func main(){
srcsli := []int{1, 2, 3, 4, 5}
destsli := make([]int, 5, 5)
fmt.Println(srcsli)
fmt.Println(destsli)
copy(destsli, srcsli)//将srcsli中的数据复制到destsli中
fmt.Println(srcsli)
fmt.Println(destsli)
destsli[3] = 10
fmt.Println(destsli)
}
package main
import "fmt"
func main(){
sli1 := make([]int, 4)//[0 0 0 0]
sli2 := sli1//俩个切片共享底层数组
sli2[0] = 100
fmt.Println(sli2[0]) //100
fmt.Println(sli1[0]) //100
fmt.Println(sli1) //[100 0 0 0]
fmt.Println(sli2) //[100 0 0 0]
}