Golang 学习笔记(一)Slice

Slice学习笔记

一、之前有学过golang的数组,然后在golang中经常使用的不是数组而是Slice,Slice是什么呢?
1、中文名叫切片,顾名思义,就像古画中的一些赝品,说它是赝品呢,却也不是,因为它是从真迹中剥落下来的一层。就如同这个一样,Slice其实就是对数组的一个切层,这一层薄如纸片,所以就叫切片(ps 方便理解而抽象出来的解释)
1.1、先来看看是如何切出来的

func main() {
	arr := [...]int{0,1,2,3,4,5,6,7}
	s := arr[2:6] // s就是arr的一个切片

那这个s里面有些什么元素呢,同python中一样,左开右闭地从arr中取下标对应的元素,所以s中就只有[2,3,4,5]这四个元素。
1.2、那既然是切下来的,有什么不同,有什么相同,又有什么联系呢?
不同点
首先,创建方式不同

func main() {
	// 创建数组
	arr := [...]int{0,1,2,3,4,5,6,7} // 不定长数组
	arr1 := [3]string{"哈哈","嘿嘿","嘻嘻"} // 定长数组
	// arr2 := [3]int{1,2,3,4} 编译不通过,因为指定了长度,那里面的元素就只能小于等于指定长度
	// 切片创建
	s := []int{1,2,3} // 前面我说它是从一个数组上切下来的,那它是从哪个数组切下来的呢?可以认为它是从arr := [...]int{1,2,3}上切下来的,但是这个数组不是真实存在的,是由系统隐式创建的。
}

其次,数组的类型是由两个指标决定的,一是它的长度(不同长度数组,类型不同),二是它里面元素类型
再有,数组是没有append方法的,想要扩容数组,必须先获取它的切片,再使用append方法,只有切片才有append方法,slice的扩容机制是2倍扩容,数组是值传递的,要么使用它的指针,可以做到引用传递,而切片是引用传递(操作之后会影响原数组)

相同点
很直观的可以看到,他们的相同点就是可以容纳一组数据,是一个数据的集合,底层最终都是在内存中一段连续的空间(数组)
联系
他们之间的关系的话,前面有说到过,Slice是对一个数组的剥落下来的一层,那这层可能不完整,术语叫做视图(view),就是说Slice是数组的一个视图,它里面的元素改变会影响着所对应的数组中的元素随着改变,比如:

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

func main() {
	arr := [...]int{0,1,2,3,4,5,6,7}
	s1 := arr[2:]
	fmt.Println("s1:", s1)
	
	updateSlice(s1)
	fmt.Println("After updateSlice s1")
	fmt.Println(s1)
	fmt.Println(arr)
}
// 结果是 
s1: [2 3 4 5 6 7]
After updateSlice s1
[100 3 4 5 6 7]
[0 1 100 3 4 5 6 7]

可以看到,这里把s的第一个元素修改为了100,而s对应的数组中的那个元素(s的第一位就是数组的第三个元素)也被修改了。
切片可以再取切片,叫做ReSlice操作,而在这个操作中又一个比较有意思的情况会出现

func main() {
	arr := [...]int{0,1,2,3,4,5,6,7}
	s1 = arr[2:6] // [2,3,4,5]
	s2 = s1[3:5]
	fmt.Println(s2)
}
// 结果
[5,6]

s1取的是数组中的2-6的下标元素,即[2,3,4,5],就这四个元素,然后s2要从s1中取出下标为3-5的元素,包含两个元素,而在s1中下标为3的就已经是5了,按道理来说就只能取出5,这一个元素来,但是结果却取出了两个,竟然还包含了s1中没有的6,我们来看一个图吧
切片扩展图
可以看到s1虽然只取到了arr中4个元素,但是它可以扩展的,它可以把原来arr中后面没取到的元素全部扩展出来(扩展的元素,通过下标来取是取不到的),所以当对s1再次切片的时候,是可以切到扩展元素的。

那接着看看这个Slice的底层是怎样的呢,仍然用一张图来看吧
切片底层实现图
从图中可以看到,slice中是有一个指针的,这个指针呢指向切片中的第一个元素,len呢就是当前这个切片的实际长度,cap呢是指这个切片的最大容量长度,而这个最大容量长度呢,就是对应的从数组中切片时起始位置到数组的最后一个元素的长度。
也就是说一个切片是可以扩展的,但是只能向后扩展,不能向前,向后扩展的最大长度呢就是这个cap的值了,超出这个值就会报错。

这里简单的讲一两个slice的操作吧。
前面反复的提到过的一个append操作,就是往slice中添加元素,append操作呢必须要用一个slice去接收,如果append操作的时候超过了cap的大小,这个时候接收到的slice,它就不再是原数组的视图,系统将会生成一个隐式的数组,而这个slice就是这个隐式数组的视图(即一个全新的slice),而且这个slice的cap会是原来的2倍。
slice的复制操作
copy(目标slice,原slice)

	// 将s1复制到s2中
	copy(s2, s1)

结束语
以上就是对slice的一些个人学习理解,后续有新的理解,继续补充。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值