深入了解Golang中Slice切片的使用
作者:nil 发布时间:2023-09-25 08:59:08
写在前面
周日下午在家学习,看到一个关于切片的问题,在网上找了一些资料,做个总结。
上代码
func main() {
sl := make([]int, 0, 10)
var appenFunc = func(s []int) {
s = append(s, 10, 20, 30)
fmt.Println(s, len(sl), cap(sl))
}
fmt.Println(sl, len(sl), cap(sl))
appenFunc(sl)
fmt.Println(sl, len(sl), cap(sl))
fmt.Println(sl[:10], len(sl), cap(sl))
fmt.Println(sl[:], len(sl), cap(sl))
}
你觉得会输出什么?思考一下再往下看。
有的人觉得可能是
[] 0 10
[10 20 30] 3 10
[] 0 10
[] 0 10
[] 0 10
实际结果是
[] 0 10
[10 20 30] 0 10
[] 0 10
[10 20 30 0 0 0 0 0 0 0] 0 10
[] 0 10
是不是差别很大?这里的差别主要是第四行、第五行的结果。
第一行:比较好理解,切片没有做任何修改,值应该是:[] 0 10
第二行:也很好理解,在appendFunc函数中打印sl,结果是:[10 20 30] 3 10 第三行:由于go都是值传递,所以传到appendFunc函数中的sl其实是切片复制了一份,对原sl没有影响,所以输出结果是:[] 0 10
第四行:sl[:10]这个应该会报数组越界错误才对?怎么没有报错,而且还输出了10 20 30,但是len(sl)等于0,很奇怪
第五行:如果第四行能输出整个数组的内容,这里的sl[:]应该也能输出内容,但是为什么是空的?
分析原因
这里有2个问题:
为什么sl[0:10]能输出10个元素,并且打印出了函数中添加的元素?但是len(sl)等于0
为什么sl[:]输出空数组?
大家都知道,slice(切片)的底层实现,slice 底层存储的数据结构指向了一个 array(数组),如下图:
slice结构体定义如下
type SliceHeader struct {
Data uintptr
Len int
Cap int
}
Data:指向具体的底层数组。
Len:代表切片的长度。
Cap:代表切片的容量。
核心要记住的是:slice 真正存储数据的地方,是一个数组。slice 的结构中存储的是指向所引用的数组指针地址。
看到这里你应该明白了,传入到appendFunc函数的sl虽然是外层定义的sl的一个值拷贝,它的修改不会影响原sl的内容,但是由于Data是个指针,appendFunc函数对Data的修改自然就影响了原sl的Data,这个很好理解。
要记住一个关键点:如果传过去的值是指向内存空间的地址,是可以对这块内存空间做修改的
对于第一个问题:为什么sl[0:10]能输出10个元素?
这里跟切片访问的一个优化有关,当用s[low : high]访问切片的时候,表达式 s[low : high]
中的 high,最大的取值范围对应着切片的容量(cap),不是单纯的长度(len) 。因此调用 fmt.Println(sl[:10])
时可以输出容量范围内的值,不会出现越界。
相对的 fmt.Println(sl)
, fmt.Println(sl[:])
因为该切片 len 值为 0,没有指定最大索引值,high 则取 len 值,导致输出结果为空。
来源:https://juejin.cn/post/7188838658081259557


猜你喜欢
- 如下:data = pd.read_csv('20180201.txt',sep = '|',dtype =
- jQuery是一个非常优秀的JavaScript 框架,使用简单灵活,同时还有许多成熟的插件可供选择,它可以帮助你在项目中加入一些非常好的效
- 1、es的批量插入这是为了方便后期配置的更改,把配置信息放在logging.conf中用elasticsearch来实现批量操作,先安装依赖
- 1、编写注意(1)给函数指定描述名。(2)函数名称只包括小写字母和下划线。(3)每一个函数都应该包含简要说明其功能的注释,注释应该紧跟在函数
- 下面,我们将会介绍 2014 年最火的 21 款JavaScript 框架,专为前端开发者准备的哦:)众所周知, JavaScript 框架
- 我们以一个例子展开这个题目问题:python类对象A,先实例化一个A对象的实例b,接着给A对象添加一个类共享变量xxx,再实例化一个c,请问
- let str = '这是一个字符串[html]语句;[html]字符串很常见';alert(str.replace(/\[
- 本文实例讲述了Python开发SQLite3数据库相关操作。分享给大家供大家参考,具体如下:'''SQLite数据库
- 本文实例讲述了Python字典生成式、集合生成式、生成器用法。分享给大家供大家参考,具体如下:字典生成式:跟列表生成式一样,字典生成式用来快
- 1.string.maketrans设置字符串转换规则表(translation table) allchars = string.make
- HTML 的拖放 API 依赖 DOM 事件模型,获取拖放和放置元素的相关信息,以此实现拖放功能。我们只需要注册很少几个事件 * ,就能把任
- Python的functools模块提供了很多有用的功能,其中一个就是偏函数(Partial function)。要注意,这里的偏函数和数学
- 安装破解包:AWVS14.6.220117111破解Win&Linux&Mac.zip网盘链接:https://pan.ba
- Kafka 样式的 soap 端点Christopher Dix 所开发的“Kafka — XSL SOAP 工具箱”(请参阅 参考资料)是
- 1. 前言由于公司的一个项目是基于B/S架构与WEB服务通信,使用XML数据作为通信数据,在添加新功能时,WEB端与客户端分别由不同的部门负
- 在设计数据窗口时,在所有列的Background.Color属性中编写如下表达式: if ( IsRowNew(), 1090519039,
- PHP策略模式(Strategy Pattern)策略模式是一种行为设计模式,它允许在运行时选择算法行为的方法。该模式定义了一组算法,将每个
- 案例一 导入图片思路: 1.导入库 2.加载图片 3.创建窗口 4.显示图片 5.暂停窗口 6.关闭窗口# 1.导入库import cv2#
- 本文主要介绍了go redis之redigo的使用,分享给大家,具体如下:安装go-redis 三方库为我们封装了很多函数来执行 Redis
- 开始制作符合标准的站点,第一件事情就是声明符合自己需要的DOCTYPE。查看本站首页原代码,可以看到第一行就是:<!DOCTYPE h