本文主要介绍Go语言中
slice,主要从源码分析和常见的面试例题两个角度加深对slice的理解。文中如有描述不对或则不合理的地方,请各位大佬积极留言,我会每日及时查看并核查纠正
slice的创建
func printSlice(sli []int) {
fmt.Printf("value=%v, len=%d, cap=%d\n", sli, len(sli), cap(sli))
}
func test() {
var sli01 []int
for i := 0; i < 6; i++ {
// printSlice(sli01)
sli01 = append(sli01, 2 * i + 1)
}
fmt.Println(sli01) // [1, 3, 5, 7, 9, 11]
sli02 := []int {2, 4, 6, 8}
printSlice(sli02) // value=[2, 4, 6, 8], len=4, cap=4
sli03 := make([]int, 2)
printSlice(sli03) // value=[0, 0], len=2, cap=2
sli04 := make([]int, 2, 4)
printSlice(sli04) // value=[0, 0], len=2, cap=4
}
slice的用法
开始索引包含,结束索引不包含
func test0001() {
arr := [5]int {0, 1, 2, 3, 4}
slice01 := arr[1: 4] // [1, 2, 3]
slice02 := arr[2: ] // [2, 3, 4]
slice03 := arr[: 3] // [0, 1, 2]
slice04 := arr[ : ] // [0, 1, 2, 3, 4]
fmt.Println(slice01, slice02, slice03, slice04) // [1 2 3] [2 3 4] [0 1 2] [0 1 2 3 4]
}
slice的make,copy与append
func printSlice(sli []int) {
fmt.Printf("value=%v, len=%d, cap=%d\n", sli, len(sli), cap(sli))
}
func copySliceDemo01() {
sli01 := []int {2, 4, 6, 8}
sli02 := make([]int, 6)
printSlice(sli02) // value=[0, 0, 0, 0, 0, 0], len=6, cap=6
copy(sli02, sli01)
printSlice(sli02) // value=[2, 4, 6, 8, 0, 0], len=6, cap=6
sli02 = append(sli02[:3], sli02[4:]...)
/*
slice02[ :3]底层结构:
arr: 2 4 6 8 0 0
slice02[ :3] 2 4 6 空 空 空
slice02[4: ] 0 0
append(slice02[ :3], slice[4: ]...) 2 4 6 0 0 空
*/
printSlice(sli02) // value=[2, 4, 6, 0, 0], len=5, cap=6
}
slice与array之间的差别
slice本身没有数据,是对底层array的一个
view
数组一旦定义好,无法进行扩容等操作切片可以看成数组的一个view,数组右边容量为边界,当不越界数组的容量时候,以数组的容量视图进行计算,否则就会发生扩容一旦发生扩容,底层数组为新开辟的内存空间
func test0002() {
arr := [5]int {0, 1, 2, 3, 4}
fmt.Printf("arr=%x, len(arr)=%d, cap(arr)=%d\n", arr, len(arr), cap(arr)) // [0, 1, 2, 3, 4], 5, 5
/*
0 1 2 3 4 // len=5, cap=5
1 2 3 空 // len=3 cap=4
*/
slice01 := arr[1: 4]
fmt.Printf("slice01=%x, len(slice01)=%d, cap(slice01)=%d\n", slice01, len(slice01), cap(slice01)) // [1, 2, 3], 3, 4
/*
0 1 2 3 4 // len=5, cap=5
2 3 4 // len=3, cap=3
*/
slice02 := arr[2: ]
fmt.Printf("slice02=%x, len(slice02)=%d, cap(slice02)=%d\n", slice02, len(slice02), cap(slice02)) // [2, 3, 4], 3, 3
/*
0 1 2 3 4 // len=5, cap=5
0 1 2 空 空 // len=3, cap=5
*/
slice03 := arr[ :3]
fmt.Printf("slice03=%x, len(slice03)=%d, cap(slice03)=%d\n", slice03, len(slice03), cap(slice03)) // [1, 2, 3], 3, 5
slice04 := arr[ : ]
/*
0 1 2 3 4 // len=5, cap=5
0 1 2 3 4 // len=5, cap=5
*/
fmt.Printf("slice04=%x, len(slice04)=%d, cap(slice04)=%d\n", slice04, len(slice04), cap(slice04)) // [0, 1, 2, 3, 4], 5, 5
fmt.Println("================================")
/*
0 1 2 3 4 // len=5, cap=5 数组没有扩容概念的
2 3 4 // len=3, cap=3 append前
2 3 4 5 空 空 // len=4, cap=6 append后 按照cap*2进行扩容, 当append前的cap>=1024,按照cap*0.25进行扩容
*/
slice05 = append(slice02, 5)
fmt.Printf("arr=%x, len(arr)=%d, cap(arr)=%d\n", arr, len(arr), cap(arr)) // [0, 1, 2, 3, 4], 5, 5
fmt.Printf("slice05=%x, len(slice05)=%d, cap(slice05)=%d\n", slice05, len(slice05), cap(slice05)) // [2, 3, 4, 5], 3, 3
}
/*
0 1 2 3 4 // len=5, cap=5 数组没有扩容概念的
1 2 3 空 // len=3, cap=4 append前
1 2 3 6 7 空 空 空 // len=5, cap=8 append后 按照cap*2进行扩容, 当append前的cap>=1024,按照cap*0.25进行扩容
*/
slice06 := append(slice01, 6, 7)
fmt.Printf("arr=%x, len(arr)=%d, cap(arr)=%d\n", arr, len(arr), cap(arr)) // [0, 1, 2, 3, 4], 5, 5
fmt.Printf("slice06=%x, len(slice06)=%d, cap(slice06)=%d\n", slice06, len(slice06), cap(slice06)) // [1, 2, 3, 6, 7], 5, 8
slice源码分析
- 源码地址
array属性len属性cap属性
// slice底层实现是维护了三个属性,len/cap属性对应的值是值类型;array属性对应的值是指针类型,指向的是底层的数组Array
type slice struct {
array unsafe.Pointer // 该属性(array,下面以ptr代替,防止和数组冲突)对应的值是指向底层数组的内存地址
len int // slice的长度
cap int // slice的容量
}
slice01与arr的关系
slice05与arr的关系
小测试01
// slice类型传递
func modifySliceZeroIndexData(sliceVariable []int) {
sliceVariable[0] = 1000
}
// slice可以向后扩展,但不允许向前扩展, slice[i]不可以向后扩展
func secondModifySlice(sliceVariable []int) {
fmt.Println("-------------relice demo----------------")
fmt.Println("reslice before--->", sliceVariable, cap(sliceVariable), len(sliceVariable)) // [1000, 2, 3], 4, 3
reslice01 := sliceVariable[1: ]
fmt.Println("reslice [1: ] after--->", reslice01, cap(reslice01), len(reslice01)) // [2, 3], 3, 2
reslice02 := reslice01[1: 2]
fmt.Println("reslice [1: 2] again after--->", reslice02, cap(reslice02), len(reslice02)) // [3], 2, 1
}
func sliceDemo01() {
arr := [5]int {0, 1, 2, 3, 4}
slice01 := arr[1: 4] // [1, 2, 3]
slice02 := arr[2: ] // [2, 3, 4]
slice03 := arr[: 3] // [0, 1, 2]
slice04 := arr[ : ] // [0, 1, 2, 3, 4]
fmt.Println(slice01, slice02, slice03, slice04) // [1 2 3] [2 3 4] [0 1 2] [0 1 2 3 4]
// 更新
fmt.Println("update slice before slice value=>", slice01) // [1, 2, 3]
fmt.Println("update slice before arr value =>", arr) // [0, 1, 2, 3, 4]
modifySliceZeroIndexData(slice01)
fmt.Println("update slice after slice value=>", slice01) // [1000, 2, 3]
fmt.Println("update slice after arr value>", arr) // [0, 1000, 2, 3, 4]
// reslice
secondModifySlice(slice01)
}