golang 切片 接口_一日看尽golang高级语法之slice

d1c884532463bb13c0da3fbc95145bf0.png

golang系列的文章包含多篇文章,总篇如下,其中包含各篇文章的指引

明月映江雪:golang系列——个人学习笔记总篇​zhuanlan.zhihu.com
61f97b139a2c88449ebf894f3aacf551.png

由于最近事情比较多,拖到现在才更新,另一方面,原计划这一章的内容将包括select、channel、方法、切片、范围、集合和接口等内容,但是实际写的时候才发现这根本是痴人说梦,所以将这些内容拆分讲解。那直接进入主题吧,本文将初步讲解slice有关的内容,如果同学们需要更详细的讲解,可以参考官方或其他资料,并欢迎大家一起讨论。

slice——切片

高中生物观察叶绿体时就有切片操作,即将叶片的组织切出薄薄的一片进行观察。同理,golang中的切片可以理解为切取内存的一部分,也可以类比数组的某一个连续的空间。slice在golang的实现主要与3个元素相关:指针、长度和容量。

  • 指针:指向某存储数据的连续内存空间,简单的说就是你要在哪儿切;
  • 长度:需要切的元素的数量,简单的说就是你要切多少;
  • 容量:最多能切的元素的数量,简单的说就是最多切多少,一点也不能多切。

切片的基本操作

var sliceTmp []int                            //声明,空切片,长度和容量都是0,指针为nil
sliceTmp2 := []string{"a","b","c"}       //初始化,长度和容量都是3
sliceTmp2[0] = "b"                          //修改sliceTmp2为"b","b","c"
sliceTmp2 = append(sliceTmp2,"d")  //添加元素 "b","b","c","d"
var sliceTmp3 []string = sliceTmp2   //切片拷贝

大家要记住:在任意基础切片上进行操作,如果生成新的切片和基础切片公用内存空间,那么修改公共内存空间的内容将影响所有使用该段公共内存空间的变量。下面给大家举个例子:

sliceTmp4 := []int{1,2,3,4,5,6}     //长度为6,容量为6
var sliceTmp5 = sliceTmp4[1:4]  //[2,3,4] sliceTmp5指针指向sliceTmp4[1],长度为3,容量为3
                                             //此时sliceTmp4和sliceTmp5公用[2,3,4]的内存空间
sliceTmp5[1] = 0

按照普遍逻辑,sliceTmp4理应是[1,2,3,4,5,6], sliceTmp5是[2,0,4],但实际上,sliceTmp4变成[1,2,0,4,5,6],仿佛在修改sliceTmp5的时候把sliceTmp4也修改了。实际上,sliceTmp4和sliceTmp5使用同一段内存空间注意:不能如下所示定义切片

var test []int{1,2,3,4,5,6}

但是可以使用make内建函数主动创建一个切片,如下所示,申请存储int型数据的切片,长度和容量为3和4。

var test [] int = make([]int,3,4)     //注意,使用make后已经存在3个元素,make([]int,0,4)则无元素

我们也可以用如下方式获取切片的长度和容量:

len(test)    //3
cap(test)   //4

切片的扩容

切片是支持动态扩容的,扩容的办法有2个:复制和追加

//复制, 新的slice为原来的2倍,先申请一个2倍的空间
    newSlice := make([]int, len(test),(cap(test)+1)*2) //避免test的容量为0
    copy(newSlice, test)
//追加, 可以直接在test上追加
    test = append(test,1,2,3) //长度和容量都加3
    newSlice = append(test,1,2,3) //newSlice为新的变量,与test没有公用空间
//一种特殊的追加方法,或者称之为合并操作
    s1 := []int{1,1}
    s2 := []int{2,2}
    s3 := append(s1,s2...) //[1,1,2,2]

切片的使用中容易出现内容公用的情形,但是只要在使用slice的时候时刻考虑切片的三个要素:指针、长度和容量,就能排查出异常的公用,否则牵一发而动全身,所有有公用内存的变量都会被改动。

切片的遍历

方法一:数组索引

for i:=0; i<len(s1); i++{
  doSomething
}

方法二:range

for index, value :=range s1{
  doSomething
}

函数传参

一般在函数传参时,我们都要尤其注意参数是传值还是传地址。在golang语言中函数传参是传值的,但是在传递切片时有点不一样。由于切片是由三个参数共同影响的,其中指针在传递后依旧为原指针,即拷贝后仍然指向同一个地址,所以当切片为参数时,原切片依然可能被函数内的操作所影响,这一点尤其要注意。

内存浪费

如前文所说,在某个基础切片上进行多次操作后,则可能产生很多个切片。假设基础切片的长度为1W,而新产生的切片长度为10,如果基础切片不会再被使用,那么建议申请长度为10的空间存储新的切片,这样基础切片就能被回收,否则将长期驻留在内容中,造成浪费。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值