切片
切片是一个拥有相同类型元素的可变长度的序列。他是基于数组类型做的一层封装。支持自动扩容。
切片是一个引用类型,他内部保护地址、长度和容量。其中容量必须要比长度大。
切片定义
var name[]T
// 例子
var a[]string
var b[]int{} //声明并初始化
var c[]bool{false,true}
// 其中a==nil b和c都!=nil
切片的长度和容量
切片用于自己的长度和容量,使用len()求长度,使用cap()求容量
基于数组定义切片
func main(){
a := [5]int{1,2,3,4,5}
b := a[1:4] // 基于数组创建切片,包含2,3,4
c := a[1:] // 2,3,4,5
d := a[:4] // 1,2,3
e := a[:] // 1,2,3,4,5
}
切片再切片
func main() {
//切片再切片
a := [...]string{"北京", "上海", "广州", "深圳", "成都", "重庆"}
fmt.Printf("a:%v type:%T len:%d cap:%d\n", a, a, len(a), cap(a))
b := a[1:3]
fmt.Printf("b:%v type:%T len:%d cap:%d\n", b, b, len(b), cap(b))
c := b[1:5]
fmt.Printf("c:%v type:%T len:%d cap:%d\n", c, c, len(c), cap(c))
}
// 切片本身是没有数据的,是对底层数组的一个视图。不能切过数组的长度。
新切片长度和容量计算公式为:底层数组容量为k的切片slice[i:j]来说,其长度为:j-i 容量为:k-i
使用make()函数构造切片
make([]T,size,cap)
a := make([]int,2,10) // 创建一个长度为2,容量为10,类型为int的切片
切片的本质
对底层数组的封装,包含三个信息:
- 地址(切片中第一个元素指向的内存空间);
- 大小(切片中目前的元素个数);
- 容量(底层数组最大存放元素的个数)。
切片不能直接比较
切片不能使用==来判断两个切片是否有全部相等的元素。当一个切片没有底层数组时为nil,一个nil的长度和容量都为0。但不能说一个长度和容量为0的是nil。如果要判断一个切片是否为空,使用len(s)==0来判断,不能使用s==nil判断
var s1[]int //len(s1)=0;cap(s1)=0;s1==nil
s2 := []int{} //len(s2)=0;cap(s2)=0;s1!=nil
s3 := make([]int,0) //len(s3)=0;cap(s3)=0;s1!=nil
切片的赋值拷贝
func main(){
s1 := make([]int,3)
s2 = s1
s2[0] = 100
fmt.Println(s1) // [100 0 0]
fmt.Println(s2) // [100 0 0]
}
切片遍历
func main() {
a := []string{"北京", "上海", "广州", "深圳", "成都", "重庆"}
for i:=0;i<len(a);i++{
fmt.Println(a[i])
}
for index,value := range a{
fmt.Println(index,value)
}
}
append()方法添加元素
Go语言的内建函数append()
可以为切片动态添加元素。 每个切片会指向一个底层数组,这个数组能容纳一定数量的元素。当底层数组不能容纳新增的元素时,切片就会自动按照一定的策略进行“扩容”,此时该切片指向的底层数组就会更换。“扩容”操作往往发生在append()
函数调用时。
func main() {
var numSlice []int
for i := 0; i < 10; i++ {
numSlice = append(numSlice, i)
}
fmt.Println(numSlice)
}
var citySlice []string
// 追加一个元素
citySlice = append(citySlice, "北京")
// 追加多个元素
citySlice = append(citySlice, "上海", "广州", "深圳")
// 追加切片
a := []string{"成都", "重庆"}
citySlice = append(citySlice, a...) // 追加切片后边要加...
fmt.Println(citySlice) //[北京 上海 广州 深圳 成都 重庆]
注意:当append在原数组上还有空位时,则一同修改原数组值;如果超过原数组长度则创建新的底层数组。
slice := []int{10, 20, 30, 40, 50}
newSlice := slice[1:3]
newSlice = append(newSlice, 60)
fmt.Println(slice, newSlice)
slice1 := []int{10, 20, 30, 40}
newSlice1 := append(slice1, 50)
fmt.Println(slice1,newSlice1)
append()防止底层数组共享方法
func main(){
source := []string{"Apple", "Orange", "Plum", "Banana", "Grape"}
slice := source[2:3:3]
fmt.Printf("slice:%v len:%d cap%d\n",slice,len(slice),cap(slice))
slice = append(slice, "pear")
fmt.Printf("slice:%v len:%d cap:%d\n", slice, len(slice), cap(slice))
fmt.Println(source)
}
使用copy()函数复制切片
由于切片是引用类型,所以当我们复制切片的时候使用copy()来操作,如果单纯的a:=b会在修改切片a时使b也修改。
copy(destSlice,srcSlice []T) // srcSlice:数据来源切片 destSlice:目标切片
func main(){
a := []int{1,2,3,4,5}
c := make([]int,5,5)
copy(c, a)
c[0] = 100
fmt.Println(a) // 1 2 3 4 5
fmt.Println(b) // 100 2 3 4 5
}
从切片中删除元素
Go语言中没有删除切片元素的方法,所以我们使用切片特性来进行操作 a = append(a[:index],a[index+1,]...)
func main(){
a := []int{1,2,3,4,5}
// 删除索引为2的元素
a = append(a[:2],a[3:]...)
fmt.Println(a) // 1 2 4 5
}