切片
先说说数组的缺点:
- 长度固定
- 做为参数传递的时候要拷贝整个数组
而切片就是为此诞生的。
切片,简单地说就是将数组切割,只取一部分用。
定义切片
package main //必须有个main包
import "fmt"
func main() {
array := []int{1, 2, 3, 4, 5} //定义数组
//通过截取数组定义切片
slice := array[0:3:5] //low:high:max 取low到high-1这几个值,最多取5个 切片长度就是high-low
fmt.Println(slice)//[1 2 3]
//slice_1 := array[0:9] //超过长度会报错
slice_1 := array[0:3]
fmt.Println(slice_1)//[1 2 3]
slice_2 := array[0]
fmt.Println(slice_2)//1
slice_3 := array[:3]//省略low则是0
fmt.Println(slice_3)//[1 2 3]
slice_4 := array[3:]//省略high则是max
fmt.Println(slice_4)//[4 5]
//直接定义切片
//slice1 := []int //这样写不对
var slice1 []int
fmt.Println(slice1)//[]
slice2 := []int{}
fmt.Println(slice2)//[]
slice4 := []int{1, 2, 3} //创建切片并初始化
fmt.Println(slice4)//[1 2 3]
slice3 := make([]int, 0 , 5)//类型,len,cap,cap可以省略
fmt.Println(slice3) //[]
fmt.Println(len(slice3))//0
fmt.Println(cap(slice3))//5
}
cap和len的区别
简单点说,len(sli)表示可见元素有几个(即直接打印元素看到的元素个数),而cap(sli)表示所有元素有几个,比如:
arr := []int{2, 3, 5, 7, 11, 13}
sli := arr[1:4]
fmt.Println(sli) //[3 5 7]
fmt.Println(len(sli))//3
fmt.Println(cap(sli))//5
切片和底层数组
同一个数组可以生成多个切片,当修改A切片时,底层数组会直接变,如果B切片刚好引用了同一个地方,则也会被改变。
package main //必须有个main包
import "fmt"
func main() {
a := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
s1 := a[2:5]
s2 := s1[1:7]
s1[1] = 666
fmt.Println("s1 = ", s1) //s1 = [2 666 4]
fmt.Println("a = ", a) //a = [0 1 2 666 4 5 6 7 8 9]
s2[1] = 777
fmt.Println("s2 = ", s2) //s2 = [666 777 5 6 7 8]
fmt.Println("a = ", a) //a = [0 1 2 666 777 5 6 7 8 9]
fmt.Println("s1 = ", s1)//s1 = [2 666 777]
}
所以可以看出,切片其实是通过指针,取的底层数组的一部分数据。
append
切片还要解决数组长度固定的问题,这个时候就需要append了。
package main //必须有个main包
import "fmt"
func main() {
//append的覆盖问题
arr := [5]int{1,2,3,4,5}
s1 := arr[0:3]
fmt.Printf("len = %d, cap = %d\n", len(s1), cap(s1))//len = 3, cap = 5
fmt.Println("s1 = ", s1)//s1 = [1 2 3]
s1 = append(s1, 1)
s1 = append(s1, 2)
s1 = append(s1, 3)
fmt.Printf("len = %d, cap = %d\n", len(s1), cap(s1))//len = 6, cap = 10
fmt.Println("s1 = ", s1) //s1 = [1 2 3 1 2 3]
fmt.Println("arr = ", arr)//arr = [1 2 3 1 2]
//直接用切片则不存在,此时切片和动态数组差不多
s2 := []int{1, 2, 3}
fmt.Println("s2 = ", s2)//s2 = [1 2 3]
s2 = append(s2, 5)
s2 = append(s2, 5)
s2 = append(s2, 5)
fmt.Println("s2 = ", s2)//s2 = [1 2 3 5 5 5]
}
append通常是翻倍扩容的
package main
import "fmt"
func main() {
//如果超过原来的容量,通常以2倍容量扩容
s := make([]int, 0, 1) //容量为1
oldCap := cap(s)
for i := 0; i < 20; i++ {
s = append(s, i)
if newCap := cap(s); oldCap < newCap {
fmt.Printf("cap: %d ===> %d\n", oldCap, newCap)
oldCap = newCap
}
}
/* 输出
cap: 1 ===> 2
cap: 2 ===> 4
cap: 4 ===> 8
cap: 8 ===> 16
cap: 16 ===> 32
*/
}
copy
名义上是拷贝,其实就是直接覆盖切片。
package main //必须有个main包
import "fmt"
func main() {
srcSlice := []int{1, 2}
dstSlice := []int{6, 6, 6, 6, 6}
copy(dstSlice, srcSlice)
fmt.Println("dst = ", dstSlice)//dst = [1 2 6 6 6]
srcSlice2 := []int{6, 6, 6, 6, 6}
dstSlice2 := []int{1, 2}
copy(dstSlice2, srcSlice2)
fmt.Println("dst2 = ", dstSlice2)//dst2 = [6 6]
dstSlice2 = srcSlice2
fmt.Println("dst2 = ", dstSlice2)//dst2 = [6 6 6 6 6]
}
切片做参数
package main //必须有个main包
import "fmt"
import "math/rand"
import "time"
func InitData(s []int) {
//设置种子
rand.Seed(time.Now().UnixNano())
for i := 0; i < len(s); i++ {
s[i] = rand.Intn(100) //100以内的随机数
}
}
//冒泡排序
func BubbleSort(s []int) {
n := len(s)
for i := 0; i < n-1; i++ {
for j := 0; j < n-1-i; j++ {
if s[j] > s[j+1] {
s[j], s[j+1] = s[j+1], s[j]
}
}
}
}
func main() {
n := 10
//创建一个切片,len为n
s := make([]int, n)
InitData(s) //初始化数组
fmt.Println("排序前: ", s)
BubbleSort(s) //冒泡排序
fmt.Println("排序后: ", s)
}