1. Slice实现原理

Slice依托数组实现,底层数组对用户屏蔽,在底层数组容量不足时可以实现自动重分配并生成新的Slice。 接下来按照实际使用场景分别介绍其实现机制。

源码包中src/runtime/slice.go:slice定义了Slice的数据结构:

type slice struct {array unsafe.Pointerlen   intcap   int
}

从数据结构看Slice很清晰, array指针指向底层数组,len表示切片长度,cap表示底层数组容量。

2. Slice的使用方法

2.1 使用make创建Slice

使用make来创建Slice时,可以同时指定长度和容量,创建时底层会分配一个数组,数组的长度即容量。
例如,语句slice := make([]int, 5, 10)所创建的Slice,结构如下图所示:

该Slice长度为5,即可以使用下标slice[0] ~ slice[4]来操作里面的元素,capacity为10,表示后续向slice添加新的元素时可以不必重新分配内存,直接使用预留内存即可。

2.2 使用数组创建Slice

使用数组来创建Slice时,Slice将与原数组共用一部分内存。

例如,语句slice := array[5:7]所创建的Slice,结构如下图所示:

切片从数组array[5]开始,到数组array[7]结束(不含array[7]),即切片长度为2,数组后面的内容都作为切片的预留内存,即capacity为5。
数组和切片操作可能作用于同一块内存,这也是使用过程中需要注意的地方。

2.3 Slice 扩容

使用append向Slice追加元素时,如果Slice空间不足,将会触发Slice扩容,扩容实际上是重新分配一块更大的内存,将原Slice数据拷贝进新Slice,然后返回新Slice,扩容后再将数据追加进去。

例如,当向一个capacity为5,且length也为5的Slice再次追加1个元素时,就会发生扩容,如下图所示:

扩容操作只关心容量,会把原Slice数据拷贝到新Slice,追加数据由append在扩容结束后完成。上图可见,扩容后新的Slice长度仍然是5,但容量由5提升到了10,原Slice的数据也都拷贝到了新Slice指向的数组中。

扩容容量的选择遵循以下规则:

  • 如果原Slice容量小于1024,则新Slice容量将扩大为原来的2倍
  • 如果原Slice容量大于等于1024,则新Slice容量将扩大为原来的1.25倍

使用append()向Slice添加一个元素的实现步骤如下:

  • 假如Slice容量够用,则将新元素追加进去,Slice.len++,返回原Slice
  • 原Slice容量不够,则将Slice先扩容,扩容后得到新Slice;将新元素追加进新Slice,Slice.len++,返回新的Slice。

2.4 注意事项

  • 创建切片时可根据实际需要预分配容量,尽量避免追加过程中扩容操作,有利于提升性能
  • 切片拷贝时需要判断实际拷贝的元素个数
  • 谨慎使用多个切片操作同一个数组,以防读写冲突
  • 使用append()向切片追加元素时有可能触发扩容,扩容后将会生成新的切片

参考:《GO专家编程》

Golang语言slice实现原理及使用方法相关推荐

  1. golang语言渐入佳境[29]-math包核心方法

    1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545 ...

  2. golang切片slice详解:介绍、内存分析、定义、遍历、切片可以继续切片、切片可以动态增长、切片的拷贝及底层原理

    切片的引入 [1]切片(slice)是golang中一种特有的数据类型 [2]数组有特定的用处,但是却有一些呆板(数组长度固定不可变),所以在 Go 语言的代码里并不是特别常见.相对的切片却是随处可见 ...

  3. 三个脚编码开关c语言,编码开关的原理及使用方法

    这里附上旋转编码器 EC11的实现原理和C语言代码 https://blog.csdn.net/lovelijiapu/article/details/99584590 旋转编码开关 在电子产品中经常 ...

  4. Java语言求笛卡尔积,Java笛卡尔积算法原理与实现方法详解

    本文实例讲述了Java笛卡尔积算法原理与实现方法.分享给大家供大家参考,具体如下: 笛卡尔积算法的Java实现: (1)循环内,每次只有一列向下移一个单元格,就是CounterIndex指向的那列. ...

  5. 算法和数据结构(golang语言实现)

    算法和数据结构(golang语言实现) 第1节 选择.冒泡.插入.复杂度 选择排序 选择排序 时间复杂度为O(N^2) 额外空间复杂度O(1) 过程: arr[0-N-1]范围上,找到最小值所在的位置 ...

  6. golang 数组 最后一个_面试必问:Golang高阶Golang协程实现原理

    1 01 引言 实现并发编程有进程,线程,IO多路复用的方式.(并发和并行我们这里不区分,如果CPU是多核的,可能在多个核同时进行,我们叫并行,如果是单核,需要排队切换,我们叫并发). 1.1 进程和 ...

  7. Go Slice实现原理分析

    Go Slice实现原理分析 认识 Slice 一种可变长度的数 操作 make :创建Slice,可以提前分配内存, append:往Slice添加元素 package main import (& ...

  8. golang语言 []interface{}和interface{}

    文章目录 golang语言 []interface{} interface(接口) interface应用场景 interface{} 空接口 []interface{} golang中为什么[]st ...

  9. Go语言slice详解

    Go语言slice详解 Go语言中的slice表示一个具有相同类型元素的可变长序列,语言本身提供了两个操作方法: 创建:make([]T,len,cap) 追加: append(slice, T -) ...

最新文章

  1. 深度学习之反向传播算法
  2. 美国正式宣告将在月球建立永久存在基地
  3. 计算机学机械制图吗,机械制图与计算机绘图(少学时·任务驱动模式)
  4. 数据库还原失败System.Data.SqlClient.SqlError: 无法执行 BACKUP LOG,因为当前没有数据库备份...
  5. Leetcode(20210412-20210418 第一周 每日一题)
  6. iostat 命令查看linux磁盘I/O
  7. 程序运行实例数量的控制
  8. 把十进制转为二进制到16进制
  9. Final Michael Scofield
  10. Numpy——常用的排序函数
  11. js控制css 加载,CSS样式表的加载对于DOM解析,渲染,JS执行的阻塞问题
  12. C#在OpenGL编程中的应用--关于摩尔纹的研究
  13. c语言windows窗口程序,C语言编写windows窗口程序
  14. PS——制作 GIF动图 或是 小视频
  15. 【第一周:数据分析思维】7周成为数据分析师
  16. Rust基础-Vec用法
  17. 基金指数温度怎么算_投资指数基金的奇技淫巧——指数温度实战详解
  18. 计算机假期计划内容,2019寒假计划,超详细学习计划表
  19. 优秀新媒体文案的4种必备能力
  20. 飞利浦、TCL、海信、REASONANCE、七彩虹、Amazfit在CES展示最新新品 | 美通企业日报...

热门文章

  1. selenium3 + java 日志
  2. 克隆对象和对象的继承
  3. 绕过AppLocker系列之MSBuild的利用
  4. 重炉后-文件上传下载
  5. 通过Rancher部署并扩容Kubernetes集群基础篇一
  6. QCon速递:Xen漏洞热补丁修复、异地双活、ODPS新功能与金融互联网
  7. Memcahce(MC)系列(三)Memcached它PHP转让
  8. XML NameSpace
  9. [转]Android Service Test——简单测试例子
  10. asp.net 2.0 下的一个小技巧