Go语言中切片是如何被截取的?

截取也是创建slice的方法,可以从数组或则slice直接截取,需要指定起,止索引位置。

基于已有的slice创建新的slice对象,被称为 reslice。新的slice 和老的slice工用底层数组,新老slice对底层数组的更改都会影响到彼此。基于数组创建新的slice也是同样的效果,对数组或slice元素的更改都会影响到彼此。

值得注意的是,新老slice或则新的slice老数组相互影响的前提是共用底层数组,如果因为执行append操作使得新的slice或老的slice底层数组扩容,移动到新的位置,两者就不会相互影响了。所以关键在于两者是否共用底层数组。

	data := []int{0,1,2,3,4,5,6,7,8,9}
	slice := data[2:4:6] // data[low,high,max]

对data使用了3个索引值,截取出新的slice。这里data可以是数组或者是slice。low 是最低索引值,这里是闭区间,就是说第一个元素是data位于low索引处的元素;而high 和 max 则是开区间,表示最后一个元素只能是索引 high-1 处的元素,而最大容量则只能是索引 max-1 的元素。
要求: max >= high >= low
当high == low 时,新的slice为空。
还有一个点,high 和 max 必须在老数组或则老slice 的容量(cap)范围内。
我们可以来看一个栗子: 猜猜下面的代码,输出什么?

package main

import "fmt"

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

	s2 = append(s2, 100)
	s2 = append(s2, 200)

	s1[2] = 20

	fmt.Println(s1)
	fmt.Println(s2)
	fmt.Println(slice)
}

运行结果如下:
在这里插入图片描述
结果分析:
s1 从slice索引 2 (闭区间)到索引 5(开区间,元素真正取到索引4),长度为3,容量默认到数组结尾8。
s2 从s1的索引2 (闭区间)到索引 6(开区间,元素真正取到索引5),容量到索引7(开区间,真正取到索引6),为5.
slice , s1 , s2的关系图如下:
在这里插入图片描述
注意,slice,s1和s2三者的元素指向同一个底层数组,向s2尾部追加一个元素100:
s2 = append(s2, 100)
此时,s2的容量刚好够,直接追加。不过,这会修改原始数组对应位置的元素,这一改动数组和s1都可以看到,如下图:
在这里插入图片描述
再次向s2追加元素200
s2 = append(s2, 200)
此时,s2的容量不够了,需要进行扩容。于是,s2,重新开辟一块空间,将原来的元素复制到新的位置,扩大自己的容量。并且为了应对未来可能append带来的再次扩容,s2会在此次扩容的时候多留一些buffer,将新的容量扩大到自己的2倍,也就是 10。slice , s1, s2的关系如下图:
在这里插入图片描述
注意,s2此时的底层数组已经和 slice,s1没有关系了。最后修改s1索引为2位置的元素:
s1[2] = 20
这次操作只会影响到原始数组的相应位置的元素,影响不到s2了,它已经不在这里了,如下图:
在这里插入图片描述
最后执行打印操作,打印s1时,只会打印s1长度以内的元素。所以只会打印出3个元素,虽然它底层数组不止3个元素。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值