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

news2024/10/2 16:25:11

做了五年的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.Pointer
 len   int
 cap   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.coloradmin.cn/o/836260.html

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

相关文章

享元模式 Flyweight Pattern 《游戏编程模式》学习笔记

如果我们要存储一个树一样的数据结构&#xff0c;直觉来说我们会这么写 但是实际上我们会发现&#xff0c;哪怕森林里有千千万万的树&#xff0c;它们大多数长得一模一样。 它们使用了相同的网格和纹理。 这意味着这些树的实例的大部分字段是一样的。 那么我们就可以将树共…

C语言自定义类型 — 结构体、位段、枚举、联合

前言 本期主要对通讯录三篇博客文章进行补充 通讯录文章&#xff1a;通讯录系列文章 对结构体进行详细介绍&#xff0c;其次讲解位段、枚举、联合体 文章目录 前言一、结构体1.什么是结构体2.结构声明2.1 声明格式2.2 如何声明&#xff08;代码演示&#xff09; 3.特殊声明3.1…

css word-break

上面的一行还是可以放置很多个字符的&#xff0c;但是就是换行了。 要求填充满整行&#xff0c;超过在换行 加上word-break:break-all;就行

每日汇评:由于美国就业数据强劲,黄金可能恢复下行趋势

1、美国非农就业数据公布前&#xff0c;金价试图从三周低点反弹&#xff1b; 2、美国经济数据喜忧参半&#xff0c;推动美元和美债收益率回落&#xff1b; 3、金价上行空间有限&#xff0c;因日技术面走势偏空&#xff1b; 金价又将下跌一周&#xff0c;周五有望创下六周以来…

浅谈小区电动汽车充电桩管理系统设计及应用

安科瑞 华楠 摘要&#xff1a;提出了针对数量众的充电桩计算充电负荷时所需需要系数的一种替代方法&#xff0c;阐述了二者适用背景的相似性&#xff0c;并针对其可行性进行了相关论述。数發众的新能源汽车在相对集中的时间充电&#xff08;尤其是与居民用电高峰重的惰况下&…

测试人员简单使用Jenkins

一、测试人员使用jenkins干什么&#xff1f; 部署测试环境 二、相关配置说明 一般由开发人员进行具体配置 1.Repository URL&#xff1a;填写git地址 2.填写开发分支&#xff0c;测试人员可通过相应分支进行测试环境的构建部署 当多个版本并行时&#xff0c;开发人员可以通过…

devops-发布vue前端项目

回到目录 将使用jenkinsk8s发布前端项目 1 环境准备 node环境 在部署jenkins的服务器上搭建node环境 node版本 # 1.拉取 https://nodejs.org/download/release/v20.4.0/node-v20.4.0-linux-x64.tar.gz# 2.解压到/usr/local目录下 sudo tar xf v20.4.0.tar.gz -C /usr/loc…

唐刘:TiDB 研发工程实践及 TiDB 人才观丨CCF 中国数据库暑期学校

在刚刚结束的 CCF 中国数据库暑期学校上&#xff0c; PingCAP 的研发副总裁唐刘分享了在 TiDB 研发过程中的工程实践经验和人才培养方法。目前&#xff0c;TiDB 已广泛应用于各行各业&#xff0c;有着庞大的用户基数&#xff0c;面临多样化的数据处理需求。PingCAP 通过开源、敏…

Datax 数据同步-使用总结(一)

1&#xff0c;实时同步&#xff1f; datax 通常做离线数据同步使用。 目前能想到的方案 利用 linux 的定时任务时间戳的方式做增量同步。 2&#xff0c;同步速度快不快&#xff1f; 单表同步速度还是挺快的 但是如果遇到复杂的 sql 查询&#xff0c;其同步效率&#xff0c…

企业数字化转型:信息化还是数字化?

面对巨大的数字经济市场&#xff0c;全球大部分企业都开始了数字化转型进程&#xff0c;国内一半以上的企业已经将数字化转型视为下一步发展重点&#xff0c;并制定了清晰的数字化转型战略规划。 但是&#xff0c;相当一部分传统行业&#xff0c;如制造、金融、能源、化工等非数…

使用ngrok实现内网穿透

前言&#xff1a;因为公司对接的某个项目要搭建一个测试环境&#xff0c;所以使用内网穿透的方式来搭建。非常方便&#xff0c;而且还节省资源&#xff0c;最重要的是免费啊这个工具。 ngrok官网&#xff1a;https://ngrok.com/ 点击下载&#xff0c;很快就能下好。 下好之…

Postman(接口测试工具)

目录 一.基本介绍 1.Postman 是什么 2.Postman 快速入门 2.1快速入门需求说明 二.Postman 完成 Controller 层测试 需要的代码&#xff1a; Java类 request.jsp success.jsp 1. 完成请求 2. 完成请求 3. 完成请求 4. 完成请求 5. 完成请求 三.发送join 一.基本介…

【Ubuntu】Ubuntu 22.04 升级 OpenSSH 9.3p2 修复CVE-2023-38408

升级原因 近日Openssh暴露出一个安全漏洞CVE-2023-38408&#xff0c;以下是相关资讯&#xff1a; 一、漏洞详情 OpenSSH是一个用于安全远程登录和文件传输的开源软件套件。它提供了一系列的客户端和服务器程序&#xff0c;包括 ssh、scp、sftp等&#xff0c;用于在网络上进行…

机器学习深度学习——卷积神经网络(LeNet)

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位即将上大四&#xff0c;正专攻机器学习的保研er &#x1f30c;上期文章&#xff1a;机器学习&&深度学习——池化层 &#x1f4da;订阅专栏&#xff1a;机器学习&&深度学习 希望文章对你们有所帮助 卷积神…

微信朋友圈会自动点赞?

网友称微信存在bug&#xff0c;朋友圈会自动点赞&#xff1f;腾讯回应了 微信作为国内最大的网络社交平台&#xff0c;目前用户已超过11亿。 令人吃惊的是&#xff0c;拥有这么庞大用户数量的平台&#xff0c;竟然有可能存在Bug。 近日&#xff0c;#微信回应看朋友圈会自动点…

Linux性能分析工具介绍(二)--内存、进程、磁盘、IO分析

目录 一、引言 二、Linux性能分析工具介绍 ------>2.1、进程 ------>2.2、内存 ------>2.3、磁盘 ------>2.4、IO 一、引言 本章从内存、IO、进程的角度,分析linux系统的性能 二、Linux性能分析工具介绍 2.1、进程 2.1.1、top top命令可以动态查看进程…

【pandas百炼成钢】数据预览与预处理

知识目录 前言一、数据查看1 - 查看数据维度2 - 随机查看5条数据3 - 查看数据前后5行4 - 查看数据基本信息5 - 查看数据统计信息&#xff5c;数值6 - 查看数据统计信息&#xff5c;非数值7 - 查看数据统计信息&#xff5c;整体 二、缺失值处理8 - 计算缺失值&#xff5c;总计9 …

【ASP.NET MVC】使用动软(三)(11)

一、问题 上文中提到&#xff0c;动软提供了数据库的基本操作功能&#xff0c;但是往往需要添加新的功能来解决实际问题&#xff0c;比如GetModel&#xff0c;通过id去查对象&#xff1a; 这个功能就需要进行改进&#xff1a;往往程序中获取的是实体的其他属性&#xff0c;比如…

浪潮服务器硬盘指示灯显示黄色的服务器数据恢复案例

服务器数据恢复环境&#xff1a; 宁夏某市某单位的一台浪潮服务器&#xff0c;该服务器中有一组由6块SAS硬盘组建的RAID5阵列。 服务器上存放的是Oracle数据库文件&#xff0c;操作系统层面划分了1个卷。 服务器故障&初检&#xff1a; 服务器在运行过程中有两块磁盘的指示灯…

需要仔细了解公文类型和目的,以便选择合适的写作风格

撰写公文前需要仔细了解公文类型和目的&#xff0c;以便选择合适的写作风格。 不同类型的公文有不同的结构、内容和表达方式&#xff0c;需要根据具体类型和目的来选择合适的写作风格和表达方式。例如&#xff0c;通知、公告等公文需要采用简洁明了、规范严谨的表达方式&#x…