slice
切片的创建
// slice的创建 // slice的创建有三种方式,一种是通过数组来创建,一种是直接创建切片,一种是用make // slice结构体在runtime包下的slice.go里,它有三个属性, // array是个指针,指向切片中第一个元素的地址,也是返回的结果 // len是切片中元素的长度, // cap是切片的容量,即可以放多少元素, //type slice struct { // array unsafe.Pointer // len int // cap int //} func main() { // 利用字面量创建,无法指定cap, a := []int{1,2,3,4,5} fmt.Println(a, len(a), cap(a)) // 利用make创建,前四个元素为int的默认值0,后两个没有值,也没有分配空间,如果输出会报out of range的错误, b := make([]int, 4, 6) fmt.Println(b) // 利用数组创建,第三个数表示切片的容量cap,注意第三个数不写的话默认是全选, c := [7]int{1,2,3,4,5} d := c[1:3:5] fmt.Println(c, d, cap(d)) }
nil切片和空切片的区别
func main() { // 这个是nil切片,即里面的array为nil var a []int // 这个是空切片,它指向的是一个内存地址,但是它没有分配任何内存空间,即底层元素包含0个元素。 // b := make([]int, 0) 和下面是等效的, b := []int{} fmt.Println(a, b) }
append扩容规则,不止下面的规则,还与具体的数据类型有关,
// 扩容规则 // 1 若申请的容量大于2倍的旧容量,则按申请的来 // 2 否则说明小于等于2倍的旧容量,即扩容的不多,先判断长度是否小于1024, // 若小于,则最终容量为旧容量的2倍 // 若大于,则不断在就容量基础上扩容四分之一,直到满足申请的容量, // newcap += newcap / 4,如果增长的过头了,即溢出了,则按申请的来, //注意:扩容扩大的容量都是针对原来的容量而言的,而不是针对原来数组的长度而言的 func main() { a := []int{1,2,3} a = append(a, 4,5,6,7) fmt.Println(a, cap(a)) }
利用数组生成切片扩容时要避免在原数组基础上扩容导致修改原数组的数据,避免方法是利用数组生成切片时要时刻注意cap的值,扩容时要一次扩容超过cap才会拷贝数据到新的空间,
func main() { array := [4]int{10, 20, 30, 40} // 由于这里cap没有扩容,所以和原数组共用的数据,即没有新拷贝数据,扩容后也会影响原数组的值, // 但如果是直接扩容的超过原数组的cap了,则会拷贝数据到新的空间, slice := array[0:2] slice = append(slice, 111) fmt.Println(cap(slice)) newSlice := append(slice, 50) newSlice = append(slice, 50) newSlice[1] += 10 fmt.Printf("After array = %v ", array) // After array = [10 30 111 50] } // 这个里面扩容的时候超过了原数组的cap了,所以会拷贝数据到新的空间, func main() { slice := []int{10, 20, 30, 40} newSlice := append(slice, 50) fmt.Printf("Before slice = %v, Pointer = %p, len = %d, cap = %d ", slice, &slice, len(slice), cap(slice)) fmt.Printf("Before newSlice = %v, Pointer = %p, len = %d, cap = %d ", newSlice, &newSlice, len(newSlice), cap(newSlice)) newSlice[1] += 10 fmt.Printf("After slice = %v, Pointer = %p, len = %d, cap = %d ", slice, &slice, len(slice), cap(slice)) fmt.Printf("After newSlice = %v, Pointer = %p, len = %d, cap = %d ", newSlice, &newSlice, len(newSlice), cap(newSlice)) }
参考:https://halfrost.com/go_slice/
https://juejin.cn/post/6844903812331732999
1 定义方式不一样,array要规定长度或者...,slice定义时方括号内为空
2 传递方式不同,array传的是值的拷贝,slice传的是指针,