【Golang】切片的底层实现(关于slice调用append函数后分配新数组的问题)

news2025/1/13 7:33:15

问题描述

今天在写代码的时候遇到一个很奇怪的现象,先看下面两段代码

func push(a []int, v int) {
	a[1] = 2
	a = append(a, v)
}
func main() {
	a := []int{0, 1, 2}
	push(a, 3)
	fmt.Println(a)
}

结果:[0 2 2]

func push(a []int, v int) {
	a = append(a, v)
	a[1] = 2
}
func main() {
	a := []int{0, 1, 2}
	push(a, 3)
	fmt.Println(a)
}

结果:[0 1 2]

乍一看这两段代码几乎一模一样,唯一的不同在于push函数中两行代码的顺序不一致

这两段代码中有两个问题

  1. 为什么第一段代码中赋值语句起到作用,append没有起到作用
  2. 为什么第二段代码中的赋值语句和append都没有起到作用

问题分析

第一个问题:为什么第一段代码中赋值语句起到作用,append没有起到作用

首先我们要清楚Go语言中不存在引用传递,即这里的a []int是值传递,我们不妨输出一下a的地址

在这里插入图片描述
可以看到函数内外的a并不是同一个切片,那么既然不是同一个切片,为什么在第一段代码中,修改了函数内的a,函数外的a也会发生改变呢?


这里我们需要了解go语言中切片是如何实现的

可以看下图,go语言中的切片实际上是对底层数组的一个view
切片由三部分组成,分别是指向底层数组的指针ptr切片的长度len底层数组的长度cap
在这里插入图片描述
由此就可以解释为何在第一段代码中修改函数内的切片,函数外的切片也会发生改变,两个切片虽然地址不同,但是它们两个的值是相同的,也就是说它们两个内部的ptr是相同的都指向同一个底层数组,所以修改其中一个,另外一个也就会随之改变。同理,在函数内append时,函数内部的切片len增加了,但由于是值传递,所以函数外部的切片len没有改变,因此函数内部的切片append不会引起函数外部的切片改变。

第二个问题:为什么第二段代码中的赋值语句和append都没有起到作用

首先关于append为什么没有起到作用,在上面已经解释过了,这里我们重点关注为什么赋值语句也没有起到作用

原因只有一句话:切片在添加元素时如果超越cap,那么就不再是对原数组的view,系统会重新分配更大的底层数组

继续分析之前的代码,在输出地址的基础上再输出切片的len和cap
在这里插入图片描述

可以看到,在执行append之前,切片的len等于cap,执行append后,切片的长度会超过cap,此时系统会重新分配更大的数组。观察输出可以发现,执行完append后切片的cap发生了变化,与我们的设想一致,系统重新分配了一个更大的数组给切片,切片的ptr指针指向了另一个数组,与函数外的切片不再指向同一个数组,因此在函数内修改切片的值的时候对函数外的切片就不会产生影响了

更进一步,我们将切片赋予一个较大的cap,使函数内的切片再执行append后len不会超过cap,观察此时的函数外的切片是否会发生变化

在这里插入图片描述

可以看到此时函数内的赋值语句成功修改了函数外的切片的值,因为此时函数内的切片执行append后,切片的len没有超过cap,并不会分配新数组,因此后面再执行赋值语句时修改的还是函数外的数组

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/74777.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

宝塔下 nginx 支持图片放缩

要想通过nginx实现图片的放缩功能,首先需要对nginx添加http_image_filter_module模块的支持,首先查看安装的nginx是否已经支持了对应的模块 nginx -V 如图,如果返回的代码中没有包含 http_image_filter_module,则代表安装的nginx…

Docker学习笔记3(狂神)

可视化 这样我们就已经安装成功了。 我们一般选择本地的。 然后我们就可以看到这样的面板。 不过这个我们平时不会去使用,只是作为了解即可。 镜像分层的理解: 如何提交一个自己的镜像。 Commit镜像 实战测试 我们现在启动了tomcat。 我们进入了tomc…

Spring RestTemplate请求过程

文章目录前言1. RestTemplate请求整体过程2. httpRequest 创建3. doWithRequest4. execute5. http响应解析前言 目前Spring RestTemplate是常用的http请求工具类,本文简单Spring RestTemplate的请求过程。 1. RestTemplate请求整体过程 接下来以ResponseEntity e…

paddleOCR识别问题和解决方案

常见问题解答: 文本检测相关FAQ paddle ocr 常见问答 https://aistudio.baidu.com/aistudio/projectdetail/4491412 参数介绍 import argparse import os import sys import cv2 import numpy as np import paddle from PIL import Image, ImageDraw, ImageFont …

如何基于 APISIX 迭代数字智联平台

分享嘉宾:沈巍,浙大网新研发总监。 网新电气成立于 2011 年,属于浙大网新旗下,为绿色智慧交通系统解决方案的提供商。业务范围包括铁路、隧道、城市智能交通、航空、高速公路等行业。整个高铁信息化的业务分布占到了全国市场的 20…

Electron 麒麟 Linux 系统 root 账户报错

使用Electron打包成客户端在麒麟Linux 操作系统上运行,普通用户启动程序正常 使用root用户出现各种问题。总结问题如下: 1. Running as root without --no-sandbox is not supported。 解决方案: 在启动命令后面加入 --no-sandbox sudo …

为SSH远程配置固定的公网TCP端口地址【内网穿透】

由于使用免费的cpolar生成的公网地址,为随机临时地址,24小时内会发生变化,并且带宽较小,只有1M。对于需要长期SSH远程的用户来说,配置固定的公网TCP端口地址,提高带宽就很有必要。 1. 保留一个固定TCP端口地…

信息收集道道之外网信息收集

#信息收集道道之外网信息收集 从个人的角度去简单整理下打点前的信息收集那些事。从信息收集本质上来说多数内容都是大同小异,遇到坚壁时,不用死磕,毕竟条条大路通罗马(大佬们也可以说说看法~向各位大佬学习! 红队知…

业务数据LEFT JOIN 多表查询慢--优化操作

首先你会想到,给表加索引,那么mysql会给主键自动建立索引吗? 会的,当然会。 在我们查询的业务表操作的时候,表业务数据庞大起来的时候,以及left join多的时候,甚至多表关联到几十张表的时候,查…

【云原生】二进制部署k8s集群(中)搭建node节点

内容预知 连接上文 1. 部署 Worker Node 组件 1.1 work node 组件部署前需了解的节点注册机制 1.2 Worker Node 组件部署步骤 2. k8s的CNI网络插件模式 2.1 k8s的三种网络模式 K8S 中 Pod 网络通信: (1)Pod 内容器与容器之间的通信 &am…

2022年四川建筑八大员(标准员)考试试题及答案

百分百题库提供建筑八大员(标准员)考试试题、建筑八大员(标准员)考试真题、建筑八大员(标准员)证考试题库等,提供在线做题刷题,在线模拟考试,助你考试轻松过关。 1.施工项目管理目标…

[附源码]Python计算机毕业设计SSM基于框架的校园爱心公益平台的设计与实现(程序+LW)

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

java基于Springboot的学生毕业离校系统-计算机毕业设计

项目介绍 学生毕业离校系统的开发过程中,采用B / S架构,主要使用Java技术进行开发,结合最新流行的springboot框架。中间件服务器是Tomcat服务器,使用Mysql数据库和Eclipse开发环境。该学生毕业离校系统包括管理员、学生和教师。其…

【SpringBoot应用篇】SpringBoot+JasperReport导出PDF

【SpringBoot应用篇】SpringBootJasperReport导出PDFJasperReport简介JasperReport的开发步骤生命周期执行流程模板工具Jaspersoft Studio概述安装配置面板介绍基本使用模板制作编译模板入门案例环境准备导出一个最基本的PDF文件导出用户列表需求数据直接从数据库中获取数据从后…

Lombok实现原理解析

文章目录前言一、Lombok注解分析二、编译期的注解处理期三、Lombok使用方法四、自定义注解处理器1、自定义注解2、实现Processor接口3、注册注解处理器五、实战MyGetter注解1、新建Maven工程myLombok2、新建子模块myget3、新建子模块person4、编译并查看结果总结前言 相信做ja…

171-有趣的OpenAI的chatGPT小实验

最近玩了一下chatGPT 问了他很多问题 然后我问了一个问题 帮我想10个帮女朋友过生日的办法 然后AI就回复了我10种 然后我继续问了我说再来10个 他又想了10种, 所以我特别想看看他到底有没有极限 10个 20个 30个 40个 50个 60个 70个 80个 90个 100个 接下去…

秋招---SQL学习

文章目录SQL的执行顺序一般是怎样的SQL如何性能优化1.select尽量不要查询全部*,而是查具体字段2.避免在where子句中使用 or 来连接条件3.尽量使用数值替代字符串类型tinyint,int,bigint,smallint类型4.用varchar代替char那什么时候要用char不用varchar呢链接&#x…

玩转华夏数艺

这里写自定义目录标题华夏数艺简述新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是…

叶酸-葡聚糖-盐酸吡柔比星偶联物(FA-PRB-DEX-NPs)|丝裂霉素C-右旋糖酐交联物(MMC-D)

叶酸-葡聚糖-盐酸吡柔比星偶联物(FA-PRB-DEX-NPs) 产品描述:将葡聚糖,盐酸吡柔比星和叶酸按序化学合成,并进一步定量,采用体外细胞性实验(四甲基偶氮唑蓝法),观察游离盐酸吡柔比星,叶酸-葡聚糖-盐酸吡柔比星,叶酸-葡聚糖-盐酸吡柔比星游离叶酸对于不同浓度细胞株SG…

计算机毕业设计ssm+vue基本微信小程序的育教幼教知识学习系统 uniapp 小程序

项目介绍 随着互联网技术的发发展,计算机技术广泛应用在人们的生活中,逐渐成为日常工作、生活不可或缺的工具,各种管理系统层出不穷。时代对人们的知识水平和综合素质要求也越来越高了,因此出现了各种适合用户在线学习系统。广泛存在于PC系统,手机APP,电脑软件等等,其中用户量…