没错,Go 语言的函数参数没有引用传递方式

这篇文章想浅浅地讲解 Go 语言函数参数传递的值拷贝。

一句话观点

Go语言中所有传递都是值传递,严格来说并不存在引用传递的概念。传递指针只是传递指针的值,并不是引用传递,只不过通过指针可以间接修改变量的值,从而达到类似引用传递的效果。

值传递

值传递就是将参数的副本传递给函数,因此在函数内部修改参数的值,不会影响到原始变量的值。

  
func modifyValue(person Person) {  person.Name = "Alice"  
}func Test4(t *testing.T) {  person1 := Person{Name: "Bob"}  modifyValue(person1)  fmt.Println("值传递:", person1.Name) // 输出: 值传递: Bob
}

在这个例子中,modifyValue 函数接收 person 的副本,修改它的字段值并不会影响原来的 person

引用传递

要实现引用传递,可以通过传递指针来实现。

func modifyReference(person *Person) {  person.Name = "Alice"  
}func Test4(t *testing.T) {  person2 := &Person{Name: "Bob"}  modifyReference(person2)  fmt.Println("引用传递:", person2.Name) // 输出: 引用传递: Alice
}

在这个例子中,modifyReference 函数接收的是 person 指针类型的副本,修改副本指向的值,会影响到原来的。

值传递例子

下面再看一个值传递的例子。恰好最近在读《Go 语言精进之路》这本书,书里有一段讲解的方法的本质问题,案例是下面这段代码:

type field struct{ name string }  func (p *field) print() {  fmt.Println(p.name)  
}  
func main() {  data1 := []*field{{"one"}, {"two"}, {"three"}}  for _, v := range data1 {  go v.print()  }  data2 := []field{{"four"}, {"five"}, {"six"}}  for _, v := range data2 {  go v.print()  }  time.Sleep(3 * time.Second)  
}

我对上面的代码进行简单改造,改为单测方法,打印输出内存地址,改造的代码如下:

  
func (p *field) print() {  fmt.Printf("%p %s \n", p, p.name)  
}  func Test1(t *testing.T) {  data1 := []*field{{"one"}, {"two"}, {"three"}}  for _, v := range data1 {  go (*field).print(v)  }  data2 := []field{{"four"}, {"five"}, {"six"}}  for _, v := range data2 {  go (*field).print(&v)  }  time.Sleep(3 * time.Second)  
}

运行单测,看下结果:

0xc000026590 six 
0xc000026590 six 
0xc000026590 six 
0xc000026540 two 
0xc000026530 one 
0xc000026550 three 

如果你奇怪为什么第二段代码输出的全是 six,那么可以接着看下面的原因分析。

先要知道的是, for range 循环中会重复使用同一个变量 v

在第一段,data1 是一个指针数组([]*field),v 每次迭代时是指向数组中不同元素的指针。由于 v 是指针,每个元素的地址自然是不同的,因此打印出的地址不同,每个元素都可以打印出来。

在第二段,data2 是一个结构体数组([]field),而 v 是数组元素的副本。当你取 &v 时,每次获取的都是这个循环中的同一个变量的地址,所以 &v 的地址是相同的。但每次迭代时,这个地址指向的值会被更新为 data2 中当前元素的副本,在最后执行的时候,&v 执行的值就是 six

如果想让第二段输出所有元素,可以每次迭代拷贝一个 v 副本,复制给变量 s,如下:

for _, v := range data2 {  s := v  go (*field).print(&s)  
}

执行单测,输出结果如下:

0xc0000265d0 six 
0xc000026590 four 
0xc0000265b0 five 
0xc000026540 two 
0xc000026550 three 
0xc000026530 one 

在这个例子中,每次迭代都会创建新的变量 s,内存地址是不同的,所以可以全部输出。

Over!

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

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

相关文章

【Java】java 集合框架(详解)

📃个人主页:island1314 ⛺️ 欢迎关注:👍点赞 👂🏽留言 😍收藏 💞 💞 💞 1. 概述 🚀 🔥 Java集合框架 提供了一系列用于存储和操作…

GeoWebCache1.26调用ArcGIS切片

常用网址: GeoServer GeoWebCache (osgeo.org) GeoServer 用户手册 — GeoServer 2.20.x 用户手册 一、版本需要适配:Geoserver与GeoWebCache、jdk等的版本适配对照 ​ 查看来源 二、准备工作 1、数据:Arcgis标准的切片,通过…

前OpenAI首席技术官为新AI初创公司筹资;我国发布首个应用临床眼科大模型 “伏羲慧眼”|AI日报

文章推荐 2024人工智能报告.zip |一文迅速了解今年的AI界都发生了什么? 今日热点 据报道,前OpenAI首席技术官Mira Murati正在为一家新的AI初创公司筹集资金 据路透社报道,上个月宣布离职的OpenAI首席技术官Mira Murati正在为一…

2024年妈杯MathorCup大数据竞赛A题超详细解题思路

2024年妈杯大数据竞赛初赛整体难度约为0.6个国赛。A题为台风中心路径相关问题,为评价预测问题;B题为库存和销量的预测优化问题。B题难度稍大于A题,可以根据自己队伍情况进行选择。26日早六点之前发布AB两题相关解题代码论文。 下面为大家带来…

excel斜线表头

检验数据验证对象 鼠标放在检验数据 验证对象中间,altenter 之后空格 选中格子,右键单元格格式, 完成 如果是需要多分割,操作一样,在画斜线的时候会有区别,在插入里面用直线画斜线即可 在表格插入的时…

el-table相关的功能实现

1. 表格嵌套表格时&#xff0c;隐藏父表格的全选框 场景&#xff1a;当table表格设置复选&#xff08;多选&#xff09;功能时&#xff0c;如何隐藏表头的复选框&#xff0c;不让用户一键多选。 <el-table :header-cell-class-name"cellClass">// 表头复选框禁…

基于Springboot无人驾驶车辆路径规划系统(源码+定制+开发)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

雷赛L6N伺服驱动器基本参数设置——EtherCAT 总线型

1、指令脉冲设置 PA0.08代表电机转一圈&#xff0c;所需要的指令脉冲数&#xff0c;该值驱动器默认值为0&#xff0c;该值更改后断电重启后生效。 2、编码器反馈脉冲设置 PA0.11&#xff0c;代表编码器输出每转脉冲数&#xff0c;实际反馈的脉冲数做了4倍频处理&#xff0c;设…

CSS揭秘:7. 伪随机背景

前置知识&#xff1a;CSS 渐变&#xff0c;5. 条纹背景&#xff0c;6. 复杂的背景图案 前言 本篇主要内容依然是关于背景的&#xff0c;无限平铺的背景会显得整齐美观&#xff0c;但又有些呆板&#xff0c;如何实现背景的多样性和随机性&#xff0c;是本篇的核心。 一、四种颜…

LTSC版本的Windows系统没有默认图片查看工具和便笺?教你下载。

前言 最近小白在使用Windows 11 LTSC版本&#xff0c;感觉真的是嘎嘎好用。 终于等到了&#xff01;旧电脑福星——最干净的Win11官方原版系统 小白用来安装这个系统的电脑配置其实也不低&#xff1a; i5-12400&#xff08;核显输出&#xff09; 16GB DDR4 3200MHz 500GB …

植物健康,Spring Boot来助力

3系统分析 3.1可行性分析 通过对本植物健康系统实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本植物健康系统采用SSM框架&#xff0c;JAVA作为开发语言&#…

【c++篇】:从基础到实践--c++内存管理技巧与模版编程基础

✨感谢您阅读本篇文章&#xff0c;文章内容是个人学习笔记的整理&#xff0c;如果哪里有误的话还请您指正噢✨ ✨个人主页&#xff1a;余辉zmh–CSDN博客 ✨ 文章所属专栏&#xff1a;c篇–CSDN博客 文章目录 前言一.c/c内存分布二.c/c的动态内存管理方式2.1.c语言的动态内存管…

Rust初踩坑

一、下载 到官网https://www.rust-lang.org/zh-CN/tools/install下载你需要的版本 二、安装 执行rustup-init 文件&#xff0c;选择1 按提示直到安装完成 可以通过以下命令测试&#xff1a; rustc -V # 注意的大写的 V cargo -V # 注意的大写的 V三、在VScode中…

Linux--epoll(ET)实现Reactor模式

Linux–多路转接之epoll Reactor反应堆模式 Reactor反应堆模式是一种事件驱动的设计模式&#xff0c;通常用于处理高并发的I/O操作&#xff0c;尤其是在服务器或网络编程中。 基本概念 Reactor模式又称之为响应器模式&#xff0c;基于事件多路复用机制&#xff0c;使得单个…

UDP(用户数据报协议)端口监控

随着网络的扩展&#xff0c;确保高效的设备通信对于优化网络功能变得越来越重要。在这个过程中&#xff0c;端口发挥着重要作用&#xff0c;它是实现外部设备集成的物理连接器。通过实现数据的无缝传输和交互&#xff0c;端口为网络基础设施的顺畅运行提供了保障。端口使数据通…

vuex使用modules模块化

1、main.js引入 //引入vuex import store from ./store new Vue({el: #app,router,store,components: { App },template: <App/>,data:function(){return{wbWinList: [] // 定义的变量&#xff0c;全局参数}}, })2、index.js import Vue from vue; import Vuex from …

python实战(一)——iris鸢尾花数据集分类

一、任务背景 本文是python实战系列专栏的第一篇文章&#xff0c;我们将从分类开始由浅入深逐步学习如何使用python完成常规的机器学习/深度学习任务。iris数据集是经典的机器学习入门数据集&#xff0c;许多分类任务教程都会以这个数据集作为示例&#xff0c;它的数据量是150条…

路由器 相关知识

一、路由器是什么 参考&#xff1a;图解系列--路由器和它庞大的功能_路由功能-CSDN博客 路由器是指&#xff1a;主要负责 OSI参考模型中网络层的处理工作&#xff0c;并根据路由表信息在不同的网络 之间转发IP 分组的网络硬件(图3-1)。这里的网络一般是指IP 子网&#xff0c;…

Redis 发布订阅 总结

前言 相关系列 《Redis & 目录》&#xff08;持续更新&#xff09;《Redis & 发布订阅 & 源码》&#xff08;学习过程/多有漏误/仅作参考/不再更新&#xff09;《Redis & 发布订阅 & 总结》&#xff08;学习总结/最新最准/持续更新&#xff09;《Redis &a…

回顾项目测试全过程,测试如何回答“测完了吗?”

“测完了吗&#xff1f;” 是系统测试岗位同学经常被问到的问题&#xff0c;提问的人可能是合作的研发&#xff0c; 合作的产品经理&#xff0c;甚至是项目的业务方&#xff0c;也有可能是测试自己。 这个问题至少有两层意思&#xff0c;不仅问新功能测试进度是否完成&#xf…