Go 语言切片遍历地址会发生改变吗?

引言:今天面试的时候,面试官问了一道学 Go 语言的同学都会的简单代码,是关于 Go 语言 for 循环问题的,他询问了一个点,循环中共享变量的地址会发生改变吗?

相信听到这个问题的你,第一反应肯定是不会变啊,怎么会发生改变呢?听到这里面试官选择摇了摇头,那到底是怎么回事呢?接下来我们来研究一下。

题目

Go 语言切片遍历地址会发生改变吗?

推荐解析

正文

首先是下面这段代码,这段代码相信很多在学习 Go 语言的同学都有接触过,那么我们现在来问一个问题,就是在

for 循环中,v 的地址会发生改变吗?

package mainimport ("fmt""runtime"
)func main() {slice := make([]int, 3, 5)fmt.Println(runtime.Version())fmt.Println("---------------------")for i, v := range slice {fmt.Printf("%p\n", &v)fmt.Println(i)}
}

在此之前,问过一些学习 Go 的同学,如下图所示:

这位学习 Go 的同学第一直觉就是不会变的,那我们现在来运行一下看看结果:

我们会发现,这个关于 v 地址打印的内容,其是会发生改变的,相信很多人第一反应都是不敢相信的的,我们再来测试一组数据:

这次我们会发现,v 的地址又没有改变了,这是怎么回事呢?我们回到原文,将两次运行结果复制下来对比一下:

第一次运行结果:
go1.22.1
---------------------
0xc00000a100
0
0xc00000a110
1
0xc00000a120
2==========================第二次运行结果:
go1.21.2
---------------------
0xc00000a100
0
0xc00000a100
1
0xc00000a100
2

我们会发现一个很关键的点,就是第一次运行结果和第二次运行结果关于 Go 语言的版本号有所不同,到这里我们就可以得出一个初步结论,go 语言 1.22 之后与 1.22 之前的版本是存在差异的,即在 1.22 之前,for 循环遍历循环变量是不会发生改变的,1.22 以及之后的版本都是会进行改变的,那改变的原因是什么呢,我们继续来探究一下。

探究

谷歌每次发布 Go 语言的新版本都会发布博客,首先我们来看一下谷歌发布的博客

谷歌 Go 1.22 博客地址:https://golang.google.cn/blog/go1.22

我们会发现其已经发生了改变了,然后我们将官方 Demo 截取下来:

func main() {done := make(chan bool)values := []string{"a", "b", "c"}for _, v := range values {go func() {fmt.Println(v)done <- true}()}// wait for all goroutines to complete before exitingfor _ = range values {<-done}
}

期望输出

这段代码在 go 1.21 版本运行的时候,可能会报一个错误,即 loop variable v captured by func literal

但是其还是会输出的,运行结果如下:

c
c
c

但如果使用 1.22 版本输出的话,顺序随机,但是每个值都会输出

a
c
b

共享变量

到这里我们大概就知道了,在 Go 1.22 之前,循环闭包共享的是同一个变量,而 1.22 之后,其不再共享同一个变量,这里我们再打印地址测试一下,代码如下:

package mainimport ("fmt""runtime"
)func main() {done := make(chan bool)values := []string{"a", "b", "c"}fmt.Println("Go Version:", runtime.Version())for _, v := range values {go func() {fmt.Println(&v)done <- true}()}// wait for all goroutines to complete before exitingfor _ = range values {<-done}
}

运行结果如下:

Go Version: go1.22.1
0xc0000260a0
0xc000026080
0xc000026090
=======================
Go Version: go1.21.2
0xc000026080
0xc000026080
0xc000026080

总结

到这里,我们就探究完毕了,Go 1.22 之后,for 循环的循环变量不再共享了,因此循环变量的地址也会发生改变。

最后

最后,我们回到一开始的问题,for 循环遍历切片,循环变量的地址会发生改变吗?这个时候我们需要回答到关于版本变更的问题,即在 1.22 之前,循环变量的地址是共享的,不会发生改变,在 1.22 之后,循环变量的地址不再是共享的,是会发生改变的。

其他补充

鱼聪明 AI 的回答:

鱼聪明 AI 地址:https://www.yucongming.com/

在 Go 语言中,切片(slice)是一个引用类型(reference type)。当你遍历切片时,遍历过程中获取的元素地址不会改变,因为切片本身并不会重新分配内存或改变其底层数组的地址。

具体来说:

  • 切片包含了一个指向数组的指针(或称为引用),以及切片的长度和容量。
  • 当你通过索引访问切片的元素时,实际上是访问底层数组中对应索引位置的元素。
  • 切片的底层数组在不需要扩展容量时,其地址是固定的,因此切片的元素地址在遍历过程中是稳定的。

例如,考虑以下示例代码:

package mainimport "fmt"func main() {nums := []int{1, 2, 3, 4, 5}for i := range nums {fmt.Printf("Element at index %d has address: %p\n", i, &nums[i])}
}

在这个例子中,切片 nums 的每个元素地址在整个循环过程中保持不变,因为 nums 持有的是底层数组的引用,而不是元素本身的复制。

总结来说,Go 语言中遍历切片获取元素的地址是安全的,因为切片的底层数组地址不会随着遍历过程发生改变。

欢迎交流

本文主要介绍 Go 语言切片遍历地址是否会发生改变的问题,在文末还有剩余三个思考题,欢迎小伙伴在评论区进行留言!近期面试鸭小程序已全面上线,想要刷题的小伙伴可以积极参与!

1)for range 循环遍历 slice 有什么问题?

2)如果对切片进行 for range 遍历的时候,遍历过程中追加的元素会不会遍历到?

3)对于需要跨版本兼容的 Go 代码,如何处理循环变量在不同版本中的行为差异?

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

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

相关文章

Webpack: 深入理解图像加载原理与最佳实践

概述 图形图像资源是当代 Web 应用的最常用、实惠的内容、装饰元素之一&#xff0c;但在 Webpack 出现之前对图像资源的处理复杂度特别高&#xff0c;需要借助一系列工具(甚至 Photoshop)完成压缩、雪碧图、hash、部署等操作。 而在 Webpack 中&#xff0c;图像以及其它多媒体…

基于MongoDB的电影影评分析

项目源码及资料 项目介绍 1、从豆瓣网爬取Top10的电影数据 爬取网址: https://movie.douban.com/top250 1.1 爬取Top10的影视信息 mv_data [] i 0 for x in soup.select(.item):i 1mv_name re.search(>([^<])<, str(x.select(.info > .hd > a > .tit…

【动态规划】2306. 公司命名

本文涉及知识点 动态规划汇总 LeetCode 2306. 公司命名 给你一个字符串数组 ideas 表示在公司命名过程中使用的名字列表。公司命名流程如下&#xff1a; 从 ideas 中选择 2 个 不同 名字&#xff0c;称为 ideaA 和 ideaB 。 交换 ideaA 和 ideaB 的首字母。 如果得到的两个新…

Python 面试【★★★★★】

欢迎莅临我的博客 &#x1f49d;&#x1f49d;&#x1f49d;&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

大数据可视化实验(七):Python数据可视化

目录 一、实验目的... 1 二、实验环境... 1 三、实验内容... 1 1&#xff09;绘制带颜色的柱状图。.. 1 2&#xff09;绘制堆叠柱状图。.. 3 3&#xff09;绘制数学函数曲线图。.. 4 4&#xff09;使用seaborn绘制组合图形。... 5 5&#xff09;使用Boken绘制多个三角形…

63.ThreadLocal原理

JDK8中ThreadLocal的设计 每个Thread维护一个ThreadLocalMap,这个map的key是ThreadLocal实例本身,value才是真正要存储的值Object。 Thread -> ThreadLocalMap -> <ThreadLocal实例对象, 变量副本> jdk早期设计 ThreadLocal -> ThreadLocalMap -> <T…

vmware安装debian11

安装vmware16 下载镜像 https://repo.huaweicloud.com/debian-cd/ https://repo.huaweicloud.com/debian-cd/11.7.0/amd64/iso-dvd/ 安装 安装完成之后重启&#xff0c;输入账号密码进入&#xff0c;安装ssh服务器即可使用

ManicTime(屏幕时间统计工具) 专业版值得购买吗

ManicTime 是 Windows 平台上&#xff0c;一款支持跟踪、标记用户在每个软件上所花时间的工具&#xff0c;它能自动归类生成时间使用报表&#xff0c;帮助用户分析及改善工作效率。 ManicTime 不仅会在后台记录、统计所有窗口的使用时间&#xff0c;还能自动截图存档到本地&a…

设计模式 - 原型模式,就该这样学!

目录 开始 为什么要引入原型模式 原型模式概述 原型模式代码实现&#xff08;浅拷贝&#xff09; 浅拷贝和深拷贝的区别 原型模式代码实现&#xff08;深拷贝&#xff09; 方式一&#xff1a;直接 copy 方式二&#xff1a;序列化和反序列化&#xff08;推荐&#xff09…

LeetCode 1527, 54,114

目录 1527. 患某种疾病的患者题目链接表要求知识点思路代码 54. 螺旋矩阵题目链接标签思路代码 114. 二叉树展开为链表题目链接标签前序遍历思路代码 前驱思路代码 1527. 患某种疾病的患者 题目链接 1527. 患某种疾病的患者 表 表Patients的字段为patient_id、patient_name…

C++ | Leetcode C++题解之第205题同构字符串

题目&#xff1a; 题解&#xff1a; class Solution { public:bool isIsomorphic(string s, string t) {unordered_map<char, char> s2t;unordered_map<char, char> t2s;int len s.length();for (int i 0; i < len; i) {char x s[i], y t[i];if ((s2t.coun…

Webpack: 7 款常用的性能分析工具

概述 Webpack 最大的优势在于它的功能非常强大、全面&#xff0c;加之繁荣活跃的组件生态&#xff0c;已经足够应对几乎所有 Web 构建需求&#xff0c;包括&#xff1a;SPA、MPA、SSR、桌面应用、Node 程序、WebAssemsbly、PWA、微前端等等&#xff0c;所以即使在近几年工程化…

Python | Leetcode Python题解之第205题同构字符串

题目&#xff1a; 题解&#xff1a; class Solution:def isIsomorphic(self, s: str, t: str) -> bool:dicts Counter(s)dictt Counter(t) if list(dicts.values()) ! list(dictt.values()):return Falsefor i in range(len(s)):inds list(dicts.keys()).index(s…

C#语言编写的仅有8KB大小的简易贪吃蛇开源游戏

前言 今天大姚给大家分享一款由C#语言编写的仅有8KB大小的简易贪吃蛇开源游戏&#xff1a;SeeSharpSnake。 项目特点 该仓库中的项目文件和脚本可以用多种不同的配置构建相同的游戏&#xff0c;每个配置生成的输出大小也不同。 项目源码运行 F5 运行 SeeSharpSnake项目&…

E4A视频APP源码电视盒子Coolpoint酷点电视4.5版后端苹果cms

电视盒子酷点TV版4.5影视APP源码后端对接苹果CMS&#xff0c;此版带会员功能,对接的是 如意验证1.71版苹果cms后端APP 电视TV4.5版,会员功能带注册邀请,绑定邮箱,邮箱找回密码,修改新密码,卡密充值,签到,积分兑换会员&#xff1b; 自带10个解析线路,有电视直播功能,首页滚动公…

Java教程之IO模式精讲,NIO+BIO

第一章 BIO、NIO、AIO介绍 背景 在java的软件设计开发中&#xff0c;通信架构是不可避免的&#xff0c;我们在进行不同系统或者不同进程之间的数据交互&#xff0c;或 者在高并发下的通信场景下都需要用到网络通信相关的技术&#xff0c;对于一些经验丰富的程序员来说&#x…

第11章 规划过程组(11.5创建WBS)

第11章 规划过程组&#xff08;一&#xff09;11.5创建WBS&#xff0c;在第三版教材第380~383页&#xff1b; 文字图片音频方式 视频22 第一个知识点&#xff1a;主要输入 1、项目管理计划 范围管理计划 定义了如何根据项目范围说明书创建WBS2、项目文件 项目范围说明…

十六进制计数器

目录 描述 输入描述&#xff1a; 输出描述&#xff1a; 参考代码 描述 请用Verilog设计十六进制递增计数器电路&#xff0c;每个时钟周期递增1。 电路的接口如下图所示。Q[3:0]中&#xff0c;Q[3]是高位。 接口电路图如下&#xff1a; 输入描述&#xff1a; input …

操作系统期末复习考题三(不挂科系列)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、前言&#x1f680;&#x1f680;&#x1f680;二、正文☀️☀️☀️三、总结&#x1f353;&#x1f353;&#x1f353; 一、前言&#x1f680;&#x1f680;&am…

java基于ssm+jsp 房屋租赁系统

1 管理员登录 管理员输入个人的用户名、密码登录系统&#xff0c;这时候系统的数据库就会在进行查找相关的信息&#xff0c;如果我们输入的用户名、密码不正确&#xff0c;数据库就会提示出错误的信息提示&#xff0c;同时会提示管理员重新输入自己的用户名、密码&#xff0c;…