golang函数传参——值传递理解

做了五年的go开发,却并没有什么成长,都停留在了业务层面了。一直以为golang中函数传参,如果传的是引用类型,则是以引用传递,造成这样的误解,实在也不能怪我。我们来看一个例子,众所周知,slice是个引用类型,我们以slice为例。

package main
​
import "fmt"
​
func main() {strSlice := make([]string, 0,10)strSlice = append(strSlice, "初始值")//打印一下没有在函数内部修改的初始情况fmt.Println("strSlice:",strSlice,"strSlice地址:",&strSlice[0])//在函数内部修改初始slice内容,再打印change(strSlice)fmt.Println("strSlice:",strSlice,"strSlice地址:",&strSlice[0])
}
func change(str []string){fmt.Println("函数传参地址:",&str[0])str[0]="改掉这个内容"
}

猜猜,打印出来的会是什么结果?

 

​不管你是怎么看,如果只有这么一个案例,就很容易产生误解。打印的函数参数的地址和外部slice的地址是一致,并且在函数体内修改的值的确影响了slice的值,由此现象很容易得出是引用传递

事实果真如此么?我们再来看一个案例。

package main
​
import "fmt"
​
func main() {strSlice := make([]string, 0,10)strSlice = append(strSlice, "初始值")//打印一下没有在函数内部修改的初始情况fmt.Println("strSlice:",strSlice,"strSlice地址:",&strSlice[0])//在函数内部修改初始slice内容,再打印change(strSlice)fmt.Println("strSlice:",strSlice,"strSlice地址:",&strSlice[0])
}
func change(str []string){fmt.Println("函数传参地址:",&str[0])str=append(str,"新增一个内容")
}

 如果是引用传递,那么经过change函数追加了值的strSlice应该是能打印出追加的值。好了,我们直接看结果。

结果,很是出乎我的意料之外啊,竟然不是像我上面猜想的那样。由此至少可以得出一个结论,golang中函数的参数传递不是引用传递。那么,也就是说即使参数是引用类型,也是值传递,既然是值传递,第一个案例作何理解呢?第二个案例又如何理解呢?

我们看一下slice的底层结构。

//go 1.20.3 path: /src/runtime/slice.go
type slice struct {array unsafe.Pointerlen   intcap   int
}

 array 是一个指向底层数组的指针,这个数组存储着切片中的元素。len 表示切片的长度,即切片中元素的数量。cap 表示切片的容量,即切片底层数组中可用的元素数量。golang的函数传参都是值传递,即使传递的是引用类型,也是对应引用类型的地址拷贝。因此,第一个案例中,实际上是把指向底层数组的指针的地址拷贝生成一个副本传到了函数体中,所以,第一个案例中修改了0xc00006c0a0地址里的内容会引发外面的参数发生变化。这个我们可以做个案例测试一下。

package main
​
import "fmt"
​
func main() {strSlice := make([]string, 0,10)strSlice = append(strSlice, "初始值")//打印一下没有在函数内部修改的初始情况fmt.Println("strSlice:",strSlice,"strSlice地址:",&strSlice[0])//在函数内部修改初始slice内容,再打印change(strSlice)fmt.Println("strSlice:",strSlice,"strSlice地址:",&strSlice[0])
}
func change(str []string){fmt.Println("函数传参地址:",&str[0])for i:=0;i<10;i++{str = append(str, fmt.Sprint(i))}fmt.Println("扩容之后的地址:",&str[0])str[0]="改掉这个内容"
}

我们知道,当slice发生扩容,runtime会开辟一块新的内存地址把内容拷贝到新的地址指向的内存中,那么,我们可以测试一下,当slice发生扩容,再修改内容,就不会影响原来的参数。

 

​实际结果,验证了我们的猜想,扩容之后,开辟新的内存地址来存放内容,因此,再修改这个参数也不会影响外部参数。

可是这个依然没有解除掉第二个案例——没有扩容时,函数内append之后外部参数打印结果和预期不符的疑惑。实际上并不矛盾,因为,slice结构中有一个变量len,这个表示slice中元素的数量,用大白话来理解就是可见的元素,传参的过程中,不仅拷贝了地址,还拷贝了len和cap,因此,虽然形参中的len发生了变化,但是并不影响实参的len。画个内存示意图来理解一下。

package main
​
import "fmt"
​
func main() {strSlice := make([]string, 0,10)strSlice = append(strSlice, "初始值")//打印一下没有在函数内部修改的初始情况fmt.Println("strSlice:",strSlice,"strSlice地址:",&strSlice[0],"len=",len(strSlice))//在函数内部修改初始slice内容,再打印change(strSlice)fmt.Println("strSlice:",strSlice,"strSlice地址:",&strSlice[0],"len=",len(strSlice))
}
func change(str []string){fmt.Println("函数传参地址:",&str[0])str=append(str,"新增一个内容")fmt.Println("形参str长度:",len(str))
}

 

直接看结果,果然验证了我们上面的猜想。

至此,函数值传递的探究到此结束。

 

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

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

相关文章

#rust taur运行报错#

场景:在window11系统上运行 tauri桌面莹应用&#xff0c;提示错误。 Visual Studio 2022 生成工具 安装的sdk11 , rust运行模式是stable-x86_64-pc-window-gnu&#xff0c; 运行npm run tauir dev 一致失败&#xff0c;失败信息如下 原因&#xff1a;1&#xff1a;在window11系…

数字图像处理(番外)图像增强

图像增强 图像增强的方法是通过一定手段对原图像附加一些信息或变换数据&#xff0c;有选择地突出图像中感兴趣的特征或者抑制(掩盖)图像中某些不需要的特征&#xff0c;使图像与视觉响应特性相匹配。 图像对比度 图像对比度计算方式如下&#xff1a; C ∑ δ δ ( i , j …

【方法】PDF可以转换成Word文档吗?如何操作?

很多人喜欢在工作中使用PDF&#xff0c;因为PDF格式可以准确地保留文档的原始格式&#xff0c;比如字体、图像、布局和颜色等。 但如果编辑文档的话&#xff0c;PDF还是没有Word文档方便。那可以将PDF转换成Word格式&#xff0c;再来编辑吗&#xff1f;如何操作呢&#xff1f;…

Vue2 第二十节 vue-router (一)

1.相关概念理解 2.基本路由 3.嵌套路由&#xff08;多级路由&#xff09; 一.相关概念理解 1.1 vue-router的理解 路由&#xff1a;就是一组key-value的对应关系, key为路径&#xff0c;value可能是function或者component多个路由&#xff0c;需要经过路由器的管理编程中的…

从0到1开发go-tcp框架【2-实现Message模块、解决TCP粘包问题、实现多路由机制】

从0到1开发go-tcp框架【2-实现Message模块、解决TCP粘包问题、实现多路由机制】 1 实现\封装Message模块 zinx/ziface/imessage.go package zifacetype IMessage interface {GetMsdId() uint32GetMsgLen() uint32GetMsgData() []byteSetMsgId(uint32)SetData([]byte)SetData…

docker容器互联详解

目录 docker容器互联详解 一、容器互联概述&#xff1a; 二、案例实验&#xff1a; 1、用户自定义的网络&#xff1a; 2、查看当前的IP信息&#xff1a; 3、启动第三个容器&#xff1a; 4、查看三个容器内部的网络&#xff1a; 5、Ping测试&#xff1a; Ps备注&#x…

wpf画刷学习1

在这2篇博文有提到wpf画刷&#xff0c; https://blog.csdn.net/bcbobo21cn/article/details/109699703 https://blog.csdn.net/bcbobo21cn/article/details/107133703 下面单独学习一下画刷&#xff1b; wpf有五种画刷&#xff0c;也可以自定义画刷&#xff0c;画刷的基类都…

web服务

静态网页与动态网页的区别 在网站设计中&#xff0c;静态网页是网站建设的基础&#xff0c;纯粹 HTML 格式的网页通常被称为“静态网页”&#xff0c;静态网页是标准的 HTML 文件&#xff0c;它的文件扩展名是 .htm、.html&#xff0c;可以包含文本、图像、声音、FLASH 动画、…

使用ffplay播放scrcpy server 视频流

使用ffplay播放scrcpy server 视频流 以windows平台为例 1 下载scrcpy windows平台安装包并解压 下载连接 2 确认版本 .\scrcpy.exe -v3 push server到Android设备 adb push scrcpy-server /data/local/tmp/scrcpy-server-manual.jar4 forward 端口 adb forward tcp:12…

局域网部署,用WorkPlus视频会议保密又安全

用户采用私有化部署视频会议软件的情况主要有以下几种因素&#xff1a; 1. 针对机密性高的会议&#xff1a;如果有涉及高度机密的商业谈判或敏感信息交流等重要会议&#xff0c;政府、军工、企业等用户会选择局域网内部署视频会议软件&#xff0c;以保证信息安全。 2. 频繁进…

iPhone 7透明屏的显示效果怎么样?

iPhone 7是苹果公司于2016年推出的一款智能手机&#xff0c;它采用了4.7英寸的Retina HD显示屏&#xff0c;分辨率为1334x750像素。 虽然iPhone 7的屏幕并不是透明的&#xff0c;但是苹果公司在设计上采用了一些技术&#xff0c;使得用户在使用iPhone 7时可以有一种透明的感觉…

自然语言处理学习笔记(一)————概论

目录 1.自然语言处理概念 2.自然语言与编程语言的比较 &#xff08;1&#xff09;词汇量&#xff1a; &#xff08;2&#xff09;结构化&#xff1a; &#xff08;3&#xff09;歧义性&#xff1a; &#xff08;4&#xff09;容错性&#xff1a; &#xff08;5&#xff0…

Docker 安装 MySQL5.6

方法一、docker pull mysql 查找Docker Hub上的mysql镜像 #docker search mysql 这里我们拉取官方的镜像,标签为5.6 #docker pull mysql:5.6 &#xff08;第一次启动Docker-MySql主要是查看Docker里面MySQL的默认配置&#xff0c;数据位置&#xff0c;日志位置&#xff0c;配…

【C++】开源:Linux端V4L2视频设备库

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍Linux端V4L2视频设备库。 无专精则不能成&#xff0c;无涉猎则不能通。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c;下…

解决一个Yarn异常:Alerts for Timeline service 2.0 Reader

【背景】 环境是用Ambari搭建的大数据环境&#xff0c;版本是2.7.3&#xff0c;Hdp是3.1.0&#xff1b;我们用这一套组件搭建了好几个环境&#xff0c;都有这个异常告警&#xff0c;但hive、spark都运行正常&#xff0c;可以正常使用&#xff0c;所以也一直没有去费时间解决这…

斯坦福大学提出在类别层级对多零件多关节三维拼装新方法

来源&#xff1a;投稿 作者&#xff1a;橡皮 编辑&#xff1a;学姐 paper&#xff1a;https://arxiv.org/pdf/2303.06163.pdf 背景&#xff1a; 形状装配通过排列一组简单或基本的零件几何图形来组成复杂的形状几何图形。许多重要的任务和应用都依赖于形状装配算法。 计算机…

棱镜七彩正式加入龙蜥社区安全联盟(OASA)

近日&#xff0c;龙蜥社区安全联盟&#xff08;OASA&#xff09;正式成立&#xff0c;棱镜七彩成为该联盟成员单位。 龙蜥社区安全联盟是促进产业合作的非营利组织&#xff0c;致力于打造中立开放、聚焦操作系统信息安全的交流平台&#xff0c;推进龙蜥社区乃至整个产业安全生态…

js实现原型链污染,沙箱绕过

一、沙箱绕过 1.概念 沙箱绕过"是指攻击者利用各种方法和技术来规避或绕过应用程序或系统中的沙箱&#xff08;sandbox&#xff09;。沙箱是一种安全机制&#xff0c;用于隔离和限制应用程序的执行环境&#xff0c;从而防止恶意代码对系统造成损害。它常被用于隔离不受信…

2023 电赛E题--可能会出现的问题以及解决方法

2023年电赛E题报告模板&#xff08;K210版&#xff09;--可直接使用 本文链接&#xff1a;2023年电赛E题报告模板&#xff08;K210版&#xff09;--可直接使用_皓悦编程记的博客-CSDN博客 解决激光笔在黑色区域无法识别 本文链接&#xff1a; 2023 电赛 E 题 激光笔识别有误-…

Stable Diffusion AI绘画学习指南【插件安装设置】

插件安装的方式 可用列表方式安装&#xff0c;点开Extensions 选项卡&#xff0c;找到如下图&#xff0c;找到Available选项卡&#xff0c;点load from加载可用插件&#xff0c;在可用插件列表中找到要装的插件按install 按扭按装&#xff0c;安装完后(Apply and restart UI)应…