当前位置: 首页 > news >正文

Go语言-切片底层探索 —— 补充篇:切片和底层数组到底是什么关系?

之前的切片探索中,上篇通过一道算法题目,了解到切片的两大特性:一是:切片是引用类型,指向底层数组,修改其底层数组的时候,会影响切片中的值。二是:向切片中添加元素的时候,切片可能会发生扩容,改变其底层指向的数组。在下篇中,我们谈到了切片的底层实现原理以及扩容机制。在之后的学习中,切片的应用场景比较多,自己也有了一些新的发现,于是形成补充篇这个文章。接下来我会从切片的几种创建方式说明切片和底层数组之间的关系、切片作为函数的参数时,实际上传递的是什么?
上下两篇:
1.GO语言-切片底层探索(上)-CSDN博客
2.GO语言-切片底层探索(下)-CSDN博客

1. 查看切片底层依托的数组

func main() {//切片slice1基于array数组创建的array := [7]int{1, 2, 3, 4, 5, 0, 1}slice1 := array[3:5]//查看array数组的信息 [1 2 3 4 5 0 0] 7 7fmt.Println(array, len(array), cap(array))//查看slice1切片的信息 [4 5] 2 4fmt.Println(slice1[:], len(slice1[:]), cap(slice1[:]))//查看slice1切片依托底层数组的信息 [4 5 0 1] 4 4fmt.Println(slice1[:cap(slice1)], len(slice1[:cap(slice1)]), cap(slice1[:cap(slice1)]))
}

 在上面的代码中,我们发现一个奇怪的现象:当我们使用切片表达式slice1[:]和slice1[:cap(slice1)]所取到的值是完全不同的。

我们常用到的切片表达式是slice[low:high]这种两个参数的形式,我们称其为简单切片表达式。此外还有一种三个参数形式的切片表达式,我们称其为扩展切片表达式,但是一般不经常使用,这里权当扩展一下。在简单切片表达式中,切片的长度length = high-low,切片的容量cap = 底层数组的长度-low。这里的low和high都是可以省略的,如果省略low则默认为0,如果省略high则默认为切片的长度,而不是容量。

slice1[:]实际上取的是切片的范围,也就是从切片的下标0到切片的长度-1。而slice1[:cap(slice1)]底层数组的范围,从slice1所依托得底层数组从下标low(这里是3,因为我们的slice1= array[3:5]),到底层数组末尾。

虽然我们在项目中一般不使用slice[:cap(slice)]这种形式,但是我们知道如果通过获取切片所依托的底层数组的方法,可以帮助我们更加清晰地理解切片和底层数组的关系,以及切片中的len和cap实际代表的是什么!

2. 切片和底层数组的关系

  1. 直接赋值方式 slice:= []int{1,2,3,4,5}
  2. make字面量方式 slice:= make([]int,0,10)
  3. 使用切片表达式根据切片或数组生成 slice:= array0[1:3]

通过之前的文章,我们知道,切片是依托于数组实现的,相比于数组而言,切片在容量不足的时候,会进行自动扩容,更具有灵活性。我们一般都是通过以上三种方式创建切片的,这三种不同的创建方式,将形成三种不同的(切片和其底层数组之间的)关系。

  1. 直接赋值创建方式,这种方式创建出来的切片长度等于容量,此时如果我们向切片中添加一个新的元素,就会触发扩容机制,改变切片指向的底层数组。
  2.  make字面量方式 slice:= make([]int,0,10),通过make创建切片,可以指定切片的长度和容量(底层数组的长度),后续向切片中添加元素的个数,如果没有超过10就不会发生扩容。通过提前指定切片的容量,可以减少程序运行过程中,切片扩容带来的资源消耗。
  3. 使用切片表达式根据切片或数组生成 slice:= array0[low:high]。使用切片表达式创建的切片,其长度为high-low,容量是底层数组的长度-low。

3. 切片作为函数的参数时,传递的是对底层数组的引用

func main() {baseArray := [5]int{1, 2, 3, 4, 5}//基于baseArray创建sliceslice := baseArray[:] modifySlice(slice, 0)fmt.Println(slice, len(slice), cap(slice))             // 输出 [100 2 3 4 5]fmt.Println(baseArray, len(baseArray), cap(baseArray)) // 输出 [100 2 3 4 5]
}func modifySlice(slice []int, index int) {slice[index] = 100
}

在代码中,我们基于baseArray创建slice,我们发现当传入的切片在函数中修改时,其依赖的底层数组也发生了修改。这说明,切片作为函数的参数时,实际上传递是对底层数组的引用。如果我们在函数的操作导致切片进行了扩容,那么我们的底层数组中的值将不会再发生变化了。

测试如下:

func main() {baseArray := [5]int{1, 2, 3, 4, 5}//基于baseArray创建sliceslice := baseArray[:]modifySlice(slice, 0)fmt.Println(slice, len(slice), cap(slice))             // 输出 [100 2 3 4 5]fmt.Println(baseArray, len(baseArray), cap(baseArray)) // 输出 [100 2 3 4 5]
}func modifySlice(slice []int, index int) {slice[index] = 100       //baseArray[index]被修改slice = append(slice, 1) //扩容,底层数组改变slice[index] = 1000      //baseArray[index]值不变fmt.Println(slice, len(slice), cap(slice)) //[1000 2 3 4 5 1] 6 10
}

4. 总结

在这篇博客中,我们主要讲解切片和底层数组之间的关系,并且通过切片的三种创建方式来进行详细的说明。我们在使用切片的时候,一定要注意切片扩容后,其底层指向的数组会发生变化,对切片的修改将不再作用与原来的底层数组。

相关文章:

  • 2024年上半年高级信息系统项目管理师考后总结
  • 以字节为单位管理文件系统
  • 961题库 北航计算机 组成原理选择题 附答案 选择题形式
  • 将 py 文件编译成 pyd 文件
  • WHAT - Typescript 中 structural-type-system 结构类型系统
  • Harmony os Next——Ble蓝牙模块
  • Linux 自动化升级Jar程序,指定Jar程序版本进行部署脚本
  • 【银角大王——Django课程——Ajax请求】
  • FJSP:波搜索算法(WSA)求解柔性作业车间调度问题(FJSP),提供MATLAB代码
  • 压测工具sysbench
  • 性能监控计算——封装带性能计算并上报的npm包(第三章)
  • 【TIPs】 Visual Stadio 2019 中本地误使用“git的重置 - 删除更改 -- hard”后,如何恢复?
  • 初识SDN
  • python-数据可视化(总)
  • Qt for Android
  • [deviceone开发]-do_Webview的基本示例
  • “寒冬”下的金三银四跳槽季来了,帮你客观分析一下局面
  • 【翻译】babel对TC39装饰器草案的实现
  • CEF与代理
  • css布局,左右固定中间自适应实现
  • golang 发送GET和POST示例
  • mysql常用命令汇总
  • RedisSerializer之JdkSerializationRedisSerializer分析
  • SwizzleMethod 黑魔法
  • TypeScript迭代器
  • 服务器从安装到部署全过程(二)
  • 复杂数据处理
  • 简单数学运算程序(不定期更新)
  • 深入浅出webpack学习(1)--核心概念
  • 网页视频流m3u8/ts视频下载
  • 优秀架构师必须掌握的架构思维
  • 在 Chrome DevTools 中调试 JavaScript 入门
  • shell使用lftp连接ftp和sftp,并可以指定私钥
  • #鸿蒙生态创新中心#揭幕仪式在深圳湾科技生态园举行
  • (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
  • (C语言)求出1,2,5三个数不同个数组合为100的组合个数
  • (Java数据结构)ArrayList
  • (安全基本功)磁盘MBR,分区表,活动分区,引导扇区。。。详解与区别
  • (论文阅读23/100)Hierarchical Convolutional Features for Visual Tracking
  • (转)为C# Windows服务添加安装程序
  • *1 计算机基础和操作系统基础及几大协议
  • .htaccess配置常用技巧
  • .NET DevOps 接入指南 | 1. GitLab 安装
  • .NET版Word处理控件Aspose.words功能演示:在ASP.NET MVC中创建MS Word编辑器
  • .NET框架
  • .net连接oracle数据库
  • .NET中的Event与Delegates,从Publisher到Subscriber的衔接!
  • // an array of int
  • /bin/rm: 参数列表过长"的解决办法
  • @AutoConfigurationPackage的使用
  • @NotNull、@NotEmpty 和 @NotBlank 区别
  • @Query中countQuery的介绍
  • [AIGC] Redis基础命令集详细介绍
  • [android] 天气app布局练习
  • [BUUCTF NewStarCTF 2023 公开赛道] week4 crypto/pwn