卷毛0基础学习Golang-基础-slice切片

卷毛0基础学习Golang-基础-slice切片

持续更新中----

切片简述

数组的长度在定义之后无法再次修改;数组是值类型,每次传递都将产生一份副本。显然这种数据结构无法完全满足开发者的真实需求。Go语言提供了数组切片(slice)来弥补数组的不足。

Slice(切片)代表变长的序列,序列中每个元素都有相同的类型。一个slice类型一般写作[]T,其中T代表slice中元素的类型;slice的语法和数组很像,只是没有固定长度而已。

数组和slice之间有着紧密的联系。一个slice是一个轻量级的数据结构,提供了访问数组子序列(或者全部)元素的功能,而且slice的底层确实引用一个数组对象。一个slice由三个部分构成:指针、长度和容量。指针指向第一个slice元素对应的底层数组元素的地址,要注意的是slice的第一个元素并不一定就是数组的第一个元素。

切片并不是数组或数组指针,它通过内部指针和相关属性引⽤数组⽚段,以实现变⻓⽅案。

slice并不是真正意义上的动态数组,而是一个引用类型。slice总是指向一个底层array,slice的声明也可以像array一样,只是不需要长度。

在这里插入图片描述

创建切片

slice和数组的区别:声明数组时,[ ]内写明了数组的长度或使用…自动计算长度,而声明slice时,[ ]内没有任何字符。经常使用的切片创建方法:

  1. 自动推导类型创建slice
    s1 := [] int {1, 2, 3, 4} 创建 有 4 个元素的切片,分别为:1234
  2. 借助make创建 slice,格式:make(切片类型,长度,容量)
    s2 := make([]int, 5, 10) len(s2) = 5, cap(s2) = 10
  3. make时,没有指定容量,那么 长度==容量
    s3 := make([]int, 5) len(s3) = 5, cap(s3) = 5
func main()  {
   s1 := [] int {1, 2, 3, 4}     // 创建 有4个元素的切片
   fmt.Println("s1=", s1)

   s2 := make([]int, 5, 10)      // 借助make创建 slice,格式:make(切片类型,长度,容量)
   s2[4] = 7
   //s2[5] = 9          		// 报错:panic: runtime error: index out of range
   fmt.Println("s2=", s2)
   fmt.Printf("len(s2)=%d, cap(s2)=%d\n", len(s2), cap(s2))

   s3 := make([]int, 5)         // make时,没指定容量,那么 长度 == 容量
   s3[2] = 3
   fmt.Println("s3=", s3)
   fmt.Printf("len(s2)=%d, cap(s2)=%d\n", len(s3), cap(s3))
}

注意:make只能创建slice、map和channel,并且返回一个有初始值(非零)的对象。

切片操作

切片截取
操作含义
s[n]切片s中索引位置为n的项
s[:]从切片s的索引位置0到len(s)-1处所获得的切片
s[low:]从切片s的索引位置low到len(s)-1处所获得的切片
s[:high]从切片s的索引位置0到high处所获得的切片,len=high
s[low:high]从切片s的索引位置low到high处所获得的切片,len=high-low
s[low : high : max]从切片s的索引位置low到high处所获得的切片,len=high-low,cap=max-low
len(s)切片s的长度,总是<=cap(s)
cap(s)切片s的容量,总是>=len(s)

截取可表示为s[low:high:max]。low:表示下标的起点。 high:表示下标的终点(左闭右开,不包括此下标)。 长度 len = high – low。容量 cap = max – low。长度对应slice中元素的数目;长度不能超过容量,容量一般是从slice的开始位置到底层数据的结尾位置。内置的len()和cap() 函数分别返回slice的长度和容量。

示例说明:

array := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
Column 1Column 2Column 2Column 2Column 2
array[:6:8][0 1 2 3 4 5]68省略 low
array[5:][5 6 7 8 9]55省略 high、 max
array[:3][0 1 2]310省略 high、 max
array[:][0 1 2 3 4 5 6 7 8 9]1010全部省略

切片和底层数组关系

func main()  {
   arr := [] int {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
   s1 := arr[2:5]             	// 从arr[2]开始,取 5-2 个元素,组成切片s1。
   fmt.Println("s1=", s1)    	// s1= [2 3 4]

   s1[1] = 666                   	// 这样将arr数组中 3 --> 666。
   fmt.Println("arr=", arr)   	// arr= [0 1 2 666 4 5 6 7 8 9]

   s2 := s1[2:7]     		// 从s1[2]开始, 取 7-2 个元素,组成 s2。
   fmt.Println("s2=", s2)    	// 实际上还是取的 数组arr。   s2= [4 5 6 7 8]

   s2[2] = 777                   	// 这会将arr中的 6 --> 777
   fmt.Println("arr=", arr)   	// arr= [0 1 2 666 4 5 777 7 8 9]
}

利用数组创建切片。切片在操作过程中,是直接操作原数组。切片是数组的引用!因此,在go语言中,我们常常使用切片代替数组。

切片做函数参数

切片作为函数参数时,传引用

func testFunc(s []int) {    // 切片做函数参数
   s[0] = -1           	// 直接修改 main中的 slice
}

func main() {
   slice := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
   fmt.Println(slice)

   testFunc(slice)          // 传引用
   fmt.Println(slice)
}

常用操作函数

append函数

append() 函数可以向 slice 尾部添加数据,可以自动为切片扩容。常常会返回新的 slice 对象:

  var s1 []int 		//创建nil切片,或者:s1 := make([]int, 0)
  
  s1 = append(s1, 1)       	//追加1个元素
  s1 = append(s1, 2, 3)    	//追加2个元素
  s1 = append(s1, 4, 5, 6) 	//追加3个元素
  fmt.Println(s1)          	//[1 2 3 4 5 6]

  s2 := make([]int, 5)
  s2 = append(s2, 6)
  fmt.Println(s2) 		//[0 0 0 0 0 6]

  s3 := []int{1, 2, 3}
  s3 = append(s3, 4, 5)
  fmt.Println(s3)		//[1 2 3 4 5]

append函数会智能的将底层数组的容量增长,一旦超过原底层数组容量,通常以2倍(1024以下)容量重新分配底层数组,并复制原来的数据。因此,使用append 给切片做扩充时,切片的地址可能发生变化。但,数据都被重新保存了,不影响使用。

func main() {
	s := make([]int, 0, 1)
	c := cap(s)
	for i := 0; i < 100; i++ {
	   s = append(s, i)
	   if n := cap(s); n > c {
	      fmt.Printf("cap: %d -> %d\n", c, n)
	      c = n
	   }
	}
}

输出结果如下:
cap: 1 -> 2
cap: 2 -> 4
cap: 4 -> 8
cap: 8 -> 16
cap: 16 -> 32
cap: 32 -> 64
cap: 64 -> 128

copy函数

函数 copy 在两个 slice 间复制数据,复制⻓度以 len 小的为准,两个 slice 指向同⼀底层数组。直接对应位置覆盖。

	data := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
	s1 := data[8:]  	//{8, 9}
	s2 := data[:5] 	//{0, 1, 2, 3, 4}
	copy(s2, s1)    	// dst:s2, src:s1
	
	fmt.Println(s2)   	//[8 9 2 3 4]
	//两个 slice 指向同⼀底层数组。直接对应位置覆盖。
	fmt.Println(data) 	//[8 9 2 3 4 5 6 7 8 9]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值