当前位置: 首页 > news >正文

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))
}

 

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

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

 

相关文章:

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

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

Liunx环境下git的详细使用(gitee版)

Liunx环境下git的详细使用&#xff08;gitee版&#xff09; 1.git是什么2.git操作2.1在gitee创建一个仓库2.2.gitignore2.3.git 3.git三板斧3.1add3.2 commit3.3push 4.git其他命令4.1查看当前仓库状态4.2查看提交日志4.3修改git里面文件名称4.4删除文件4.5修改远端仓库内容 1.…...

exoplayer的使用-2,与flutter相互通信

上一次解决的问题是ac3这些exoplayer本身不支持音频,添加了ffmpeg扩展实现软解码. 另一个问题是flutter端的内置字幕显示不了,也不打算再继续探讨了,换成native实现播放器.由于主项目是flutter的,所以涉及到了相互通信. 当前文章主要涉及到flutter与native相互通信功能 通信有…...

【基础类】—类型转换

一、数据类型 原始类型 Boolean、Null、Undefined、Number、String、Symbol 对象 Object 二、显示类型转换 Number函数&#xff0c; Number&#xff08;param&#xff09; 1-1. param 是 原始类型 时 数值&#xff1a;转换后还是原来的值 字符串&#xff1a;如果可以被解析…...

【云原生】 一文了解docker中的网络

文章目录 1.在Docker中,网络的实现方式是通过使用不同的网络驱动程序来实现的。2.桥接网络是默认网络。3.主机网络模式是不使用网络隔离的一种特殊模式。4.另一个有用的网络驱动程序是覆盖网络。5.最后,MACVLAN网络驱动程序允许多个容器与宿主机网卡的单独MAC地址和IP地址之间…...

嵌入式开发学习(STC51-15-红外遥控)

内容 使用外部中断功能&#xff0c;使按下红外遥控器&#xff0c;将对应键值编码数据解码后通过数码管显示 红外遥控介绍 红外线简介 人的眼睛能看到的可见光按波长从长到短排列&#xff0c;依次为红、橙、黄、绿、青、蓝、紫&#xff1b; 其中红光的波长范围为 0.62&…...

代码编辑器实践之vue-codemirror使用

前言 程序员用到IDE次数比较频繁&#xff0c;比如vscode、idea等&#xff0c;这些都是市场上比较流行的代码编辑器&#xff0c;拥有非常全面的功能。但是有时候在项目开发上也会用到代码编辑器&#xff0c;比如复杂的Array<Object>输入&#xff0c;或者需要用到用户交互…...

Mapstruct

1. Mapstruct介绍 1. 实体类之间对象映射中间件 2. 实体类相同结构属性自动对象映射 3. 实体类不同结构属性可以手动配置对象映射 2. Mapstruct基本使用 1. 定义一个接口或抽象类加Mapper(componentModel “spring”)&#xff1b;spring&#xff1a;可以spring框架注入 2. 定义…...

初阶C语言——特别详细地介绍函数

系列文章目录 第一章 “C“浒传——初识C语言&#xff08;更适合初学者体质哦&#xff01;&#xff09; 第二章 详细认识分支语句和循环语句以及他们的易错点 第三章 初阶C语言——特别详细地介绍函数 目录 系列文章目录 前言 一、函数是个什么鬼东西&#xff1f; 二、C语…...

pulsar-client-1-2 PulsarClient构造函数

前言 上文说到,PulsarClient通过链式调用构建,而在build()中调用了new PulsarClientImpl(conf),而Producer 本文通过解析构造函数,了解其主要结构。 // 创建PulsarClient PulsarClient client = PulsarClient.builder().serviceUrl("pulsar://localhost:6650")…...

原型链污染是什么

__proto__ 一个Foo类实例化出来的foo对象&#xff0c;可以通过foo.__proto__属性来访问Foo类的原型&#xff0c;也就是说&#xff1a; foo.__proto__ Foo.prototype 对象 构造函数 所以&#xff0c;总结一下&#xff1a; prototype是一个类的属性&#xff0c;所有…...

java之石头迷阵单击游戏、继承、接口、窗体、事件、组件、按钮、图片

文章目录 前言主方法实现类 前言 主方法和实现类在同一个包中。 主方法 package PSortGames;public class Main {public static void main(String[] args) {new MainFrame();} }实现类 package PSortGames;import javax.swing.*; import java.awt.event.KeyEvent; import jav…...

Debian 系列 Linux 的静态 DNS 、gateway 、IP 设置和网络重启

文章目录 DNS 设置DNS 配置文件DNS 配置文件内容 gateway、IP 设置网络适配器配置文件网络适配器配置文件内容 网络重启 各个 Linux 发行版的网络设置有很大不同。根据最近对 Debian 系列&#xff08;含 Debian 12、基于 Debian 12 的Proxmox 8.0-2 以及基于Debian 11 的 openm…...

IP路由基础+OSPF 基础

IP路由 RIB与FIB RIB&#xff1a;Routing Information Base&#xff0c;路由信息库 &#xff0c;路由器的控制平面 FIB&#xff1a;Forwarding Information Base&#xff0c;转发信息库&#xff0c;路由器的数据平面 路由信息库主要是记录直连路由以及协议宣告的路由信息&am…...

window远程连接Linux

Linux启用ssh服务 管理员权限进入root 安装 OpenSSH 服务器软件包 对于 Debian、Ubuntu 或基于这些发行版的系统&#xff0c;可以运行以下命令安装&#xff1a; sudo apt update sudo apt install openssh-server对于基于 Red Hat、CentOS 或 Fedora 的系统&#xff0c;可以…...

MyBatis 查询数据库之二(增、删、改、查操作)

目录 1. 配置打印 MyBatis 执行的SQL 2. 查询操作 2.1 通过用户 ID 查询用户信息、查询所有用户信息 (1) Mapper 接口 (2)UserMapper.xml 查询所有用户的具体实现 SQL (3)进行单元测试 3. 增加操作 3.1 在 mapper&#xff08;interface&#xff09;里面添加增加方法的声…...

unraid docker桥接模式打不开页面,主机模式正常

unraid 80x86版filebrowser&#xff0c;一次掉电后&#xff0c;重启出现权限问题&#xff0c;而且filebrowser的核显驱动不支持amd的VA-API 因为用不上核显驱动&#xff0c;解压缩功能也用不上&#xff0c;官方版本的filebrowser还小巧一些&#xff0c;18m左右 安装的时候总是…...

第七章:进程间通信(IPC)——构成进程间通信的信道方案

系列文章目录 文章目录 系列文章目录前言进程间通信介绍进程间通信目的进程间通信发展进程间通信分类进程通信的原理 管道什么是管道pipe管道通信特点简单设计 命名管道什么是命名管道mkfifostrcmp/strncasecmpunlinkgetch简单设计 共享内存什么是共享内存shmget/ftokipcsshmct…...

部分常用CSS样式

目录 1.字体样式 2.文本样式 3.鼠标样式 cursor 4.背景样式 5.列表样式 6.CSS伪类 7.盒子模型 1.字体样式 font-family 字体类型&#xff1a;隶书” “楷体” font-size 字体大小&#xff1a;像素px font-weight 字体粗细&#xff1a;bold 定义粗体字…...

思科单臂路由、lacp链路聚合、NAT实验

实验拓扑图&#xff1a; 实验目的&#xff1a; 如图所示配置相应IP地址和VLAN&#xff0c;并通过在AR1上配置单臂路由&#xff0c;实现VLAN10和VLAN20的主机能够在VLAN间通信&#xff1b;在SW1和SW2的三条链路实施链路聚合&#xff0c;使用静态LACP模式&#xff0c;使一条链…...

KubeSphere 容器平台高可用:环境搭建与可视化操作指南

Linux_k8s篇 欢迎来到Linux的世界&#xff0c;看笔记好好学多敲多打&#xff0c;每个人都是大神&#xff01; 题目&#xff1a;KubeSphere 容器平台高可用&#xff1a;环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件&#xff08;System Property Definition File&#xff09;&#xff0c;用于声明和管理 Bluetooth 模块相…...

uniapp微信小程序视频实时流+pc端预览方案

方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度​WebSocket图片帧​定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐​RTMP推流​TRTC/即构SDK推流❌ 付费方案 &#xff08;部分有免费额度&#x…...

HTML前端开发:JavaScript 常用事件详解

作为前端开发的核心&#xff0c;JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例&#xff1a; 1. onclick - 点击事件 当元素被单击时触发&#xff08;左键点击&#xff09; button.onclick function() {alert("按钮被点击了&#xff01;&…...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

【Java学习笔记】BigInteger 和 BigDecimal 类

BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点&#xff1a;传参类型必须是类对象 一、BigInteger 1. 作用&#xff1a;适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...

DeepSeek越强,Kimi越慌?

被DeepSeek吊打的Kimi&#xff0c;还有多少人在用&#xff1f; 去年&#xff0c;月之暗面创始人杨植麟别提有多风光了。90后清华学霸&#xff0c;国产大模型六小虎之一&#xff0c;手握十几亿美金的融资。旗下的AI助手Kimi烧钱如流水&#xff0c;单月光是投流就花费2个亿。 疯…...