第九节:切片(slice)

arr:=[...]int{0,1,2,3,4,5,6,7,8,9}
s:=arr[2:6]

其中s就是切片,slice本身是没有数据的,是对底层array的一个view。

切片的操作

func updateSlice(s []int)  {
	s[0]=100
}


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

	fmt.Println("arr",arr)
	s1:=arr[2:]
	fmt.Println("s1",s1)
	updateSlice(s1)
	fmt.Println("after updateSlice(s1)",s1)
	fmt.Println("after updateSlice() arr",arr)
}

控制台打印:

arr [0 1 2 3 4 5 6 7 8 9]
s1 [2 3 4 5 6 7 8 9]
after updateSlice(s1) [100 3 4 5 6 7 8 9]
after updateSlice() arr [0 1 100 3 4 5 6 7 8 9]

Process finished with exit code 0

可以看到,在函数内改变切片的值,原来的数组和切片中的值也改变了

对slice取slice操作

	arr:=[...]int{0,1,2,3,4,5,6,7,8,9}

	fmt.Println("arr",arr)
	s1:=arr[2:]
	fmt.Println("s1",s1)
	updateSlice(s1)
	fmt.Println("after updateSlice(s1)",s1)
	fmt.Println("after updateSlice() arr",arr)

	fmt.Println("Reslice")
	s1=s1[2:]
	fmt.Println("Reslice 1 step",s1)
	s1=s1[:3]
	fmt.Println("Reslice 2 step",s1)


控制台:

arr [0 1 2 3 4 5 6 7 8 9]
s1 [2 3 4 5 6 7 8 9]
after updateSlice(s1) [100 3 4 5 6 7 8 9]
after updateSlice() arr [0 1 100 3 4 5 6 7 8 9]
Reslice
Reslice 1 step [4 5 6 7 8 9]
Reslice 2 step [4 5 6]

Process finished with exit code 0

slice的扩展:

	arr:=[...]int{0,1,2,3,4,5,6,7,8,9}
	fmt.Println("arr:",arr)
	s2:=arr[2:6]
	fmt.Println("s2:",s2)
	s3:=s2[3:6]
	fmt.Println("s3:",s3)

上码的代码:
s2是取数组arr中第2到第六的元素,值为:2,3,4,5
s3又对s2做了切片:取s2中第3到第六的元素,但是s2总共只有四个元素,能不能拿到值呢?运行一波看看:


控制台:

arr: [0 1 2 3 4 5 6 7 8 9]
s2: [2 3 4 5]
s3: [5 6 7]

可以看到,是能拿到值的,因为slice是对arr的一个view,虽然s2中的元素不够,其实它对应的view底层还是arr数组,所以能拿到值。

 

slice的实现:

slice的其实位置指向底层arr的开始位置,如:s:=arr[2:],起始位置指向arr的2,s的len指的就是s本身的长度,如果用s[5]去取数据,5如果越界,则会报错,此外,slice还维护一个叫做cap的属性,这个属性就是对应底层的arr的长度,也就是s的可扩展长度,只要不超过这个长度,就能拿到值。

总结:slice可以向后扩展,不能向前扩展,向后扩展的长度不能超过cap(arr),s[i]通过索引取值,i不能超过len(s)。

	arr:=[...]int{0,1,2,3,4,5,6,7,8,9}
    s1:=arr[2:]
    fmt.Println("Reslice")
	s1=s1[2:]
	fmt.Printf("Reslice 1 step %d  len(s1):%d cap(s1):%d\n",s1,len(s1),cap(s1))
	s1=s1[:3]
	fmt.Printf("Reslice 2 step %d len(s1):%d cap(s1):%d\n",s1,len(s1),cap(s1))


控制台输出:

Reslice
Reslice 1 step [4 5 6 7 8 9]  len(s1):6 cap(s1):6
Reslice 2 step [4 5 6] len(s1):3 cap(s1):6

Process finished with exit code 0

可以看出:第一次切片之后,s1的len为6,cap也为6

                  第二次切片之后:s1的len为3,cap依然为6

 

切片追加数据:

	s1=s1[:3]
	fmt.Printf("Reslice 2 step %d len(s1):%d cap(s1):%d\n",s1,len(s1),cap(s1))



	s5:=append(s1,10)
	s6:=append(s5,11)
	fmt.Println(s5)
	fmt.Println(s6)
	fmt.Println("arr",arr)

控制台打印:

Reslice
Reslice 1 step [4 5 6 7 8 9]  len(s1):6 cap(s1):6
Reslice 2 step [4 5 6] len(s1):3 cap(s1):6
[4 5 6 10]
[4 5 6 10 11]
arr [0 1 100 3 4 5 6 10 11 9]

Process finished with exit code 0


可以看到,在s1后面追加了10并赋值给s5,又在s5后面追加11赋值给s6,而原来的arr也发生了变化,因为s1对arr的View是 4,5,6这三个元素,所以对s1进行append操作时会在这三个元素后面追加,把原来的7覆盖掉了。紧接着又对s5进行append操作,s5虽然是s1上的切片,但是对应底层的arr依然是arr,所以会继续追加,把arr中的元素8覆盖,最后就打印出这样的结果。

把上面的代码做一个简单的改变:

	s5:=append(s1,10)
	s6:=append(s5,11,12,13,14,15)
	fmt.Println(s5)
	fmt.Println(s6)
	fmt.Println("arr",arr)

控制台打印:

[4 5 6 10]
[4 5 6 10 11 12 13 14 15]
arr [0 1 100 3 4 5 6 10 8 9]

Process finished with exit code 0

可以发现,第一次进行追加操作成功了,arr中的元素7被覆盖为10,第二次追加了五个数,长度已经超过底层arr的长度,所以没有覆盖,但是此时go为我们新生成了一个数组来容纳这些元素。

 

总结:

添加元素时如果超过cap,编译器会自动分配更大的底层数组。

由于值传递的关系,必须接受append的返回值,也就是说,进行append操作时,比如用一个新的slice来接受append的返回新的slice,因为在append的过程中,可能发生slice的Len和cap的改变

 

 

slice的创建:

var s []int//创建一个空的slice

s1:=[]int{2,4,5,6,8}//创建一个对数组的view的slice

s2:=make([]int,16)//使用内建函数,创建一个长度为16的slice

s3:=make([]int,16,128)//创建一个Len为16,cap为128的slice

slice的拷贝:

	var s []int
	s1:=[]int{2,4,5,6,8}
	s2:=make([]int,16)
	s3:=make([]int,16,128)

	copy(s2,s1)
控制台:

[2 4 5 6 8]
[2 4 5 6 8 0 0 0 0 0 0 0 0 0 0 0]

slice的删除:

	fmt.Println("before delete",s2)
	s2=append(s2[:3],s2[4:]...)
	fmt.Println("after delete",s2)

控制台:

before delete [2 4 5 6 8 0 0 0 0 0 0 0 0 0 0 0]
after delete [2 4 5 8 0 0 0 0 0 0 0 0 0 0 0]

删除没有内建的api,只能使用append操作完成,好蛋疼啊!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值