切片(slice)的使用和细节说明

切片的基本介绍:

  1. 切片的英文名字是slice,切片是数组的一个引用,因此切片是引用类型,在进行传递时,遵守引用传递的机制。
  2. 切片的使用和数组类似,遍历,访问切片元素,切片长度都跟数组是一样的。
  3. 切片的长度是可以变化的,因此切片是一个可以动态变化的数组。
  4. 切片定义的语法: var 切片名 []类型 比如: var a []int
func main() {
//定义一个数组
var arr = [...]int{1, 2, 3, 4}
//在arr数组中定义一个切片slice,从arr数组下标1开始到下标3但是不包括3。
slice := arr[1:3]
fmt.Println("arr=", arr) //1,2,3,4
fmt.Println("slice=", slice) //2,3
fmt.Println("slice元素个数是:", len(slice)) //2
fmt.Println("slice的容量是:", cap(slice)) //3 切片的容量是可以动态变化的
}

切片在内存中的形式:

slice的确是一个引用类型,从底层来说,其实就是一个数据结构(struct结构体)。

type slice struct{
ptr *[2]int
len int
cap int
}

切片的定义方式:

func main() {
//方式1 从某个数组上引用
var arr = [...]int{1, 2, 3, 4}
slice := arr[1:3]
fmt.Println("slice=", slice)
//方式2 通过make来创建切片 对于切片必须make后才可以使用 第一个参数是数据类型,第二参数是长度,第三个参数可选是容量
//容量必须大于等于长度
var slice2 []float64 = make([]float64, 5, 10)
fmt.Println("slice2=", slice2) //slice2= [0 0 0 0 0]
//方式3 直接指定
var slice3 = []string{"tom", "marry", "jack"}
fmt.Println("slice3=", slice3)
}

方式2的内存图:

  1. 通过make方式创建的切片可以指定切片的大小和容量。
  2. 如果没有给切片的各个元素赋值,那么就会使用默认值。
  3. 通过make方式创建的切片对应的数组是有make底层维护,对外不可见,即只能通过slice去访问各个元素。

切片的遍历:

func main() {
//定义切片
var arr = [...]int{10, 20, 30, 40, 50}
slice := arr[1:4]
//方式1
for i := 0; i < len(slice); i++ {
fmt.Printf("slice[%v]=%v ", i, slice[i])
//slice[0]=20 slice[1]=30 slice[2]=40
}
fmt.Println() //换行
//方式2
for index, value := range slice {
fmt.Printf("slice[%v]=%v ", index, value)
}
}

切片的细节说明:

  1. 切片初始化时 var slice = arr[startIndex : endIndex] 说明:从arr数组下标为startIndex,取到endIndex下标的元素(不包含endIndex)。
  2. 切片初始化时,仍不能越界,范围在[0,len(arr)]之间,但是可以动态增长。
    • var slice = arr[:end] 从0-end end为指定的下标。
    • var slice = arr[start:] 从start-arr的长度 start为指定的下标。
    • var slice = arr[:] 取整个数组。
  3. cap是一个内置函数,用于统计切片的容量,即最大可以存放多少个元素。
  4. 切片定义完以后,还不能使用,因为本身是一个空的,需要让其引用到一个数组,或者Make一个空间供切面使用。
  5. 用append内置函数,可以对切片进行动态追加。
func main() {
//定义切片
var slice = []int{100, 200, 300}
//给切片追加元素 返回的是一个新的切片
slice2 := append(slice, 400, 500, 600)
fmt.Println("slice=", slice) //slice= [100 200 300]
fmt.Println("slice2=", slice2) //slice2= [100 200 300 400 500 600]
//可以把slice追加给slice2
slice2 = append(slice2,slice...)
fmt.Println("slice2=", slice2) //slice2= [100 200 300 400 500 600 100 200 300]
}

append原理分析:

append操作的本质其实就是对数组的扩容,go底层会创建一个新的数组newArr(按照扩容后的大小),将slice原来包含的元素拷贝到新的数组newArr,然后追加新的元素到新数组中,slice重新引用到newArr,注意newArr是在底层维护的,程序员不可见。
6. 用copy内置函数可以进行切片拷贝。拷贝出来的切片和源数组的数据空间是独立的互不影响。

func main(){
//定义切片
var slice = []int{100, 200, 300}
slice3 := make([]int, 10) //指定切面的长度是10
//把slice切片的元素赋值给slice3切片
copy(slice3, slice)
fmt.Println("slice3=", slice3)//slice3= [100 200 300 0 0 0 0 0 0 0]
}
  1. 切片是引用类型,所以在传递的时候,遵守引用传递机制。
posted @   程序马2023  阅读(240)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示