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

go函数传值是值传递?还是引用传递?slice案例加图解

先说下结论

Go语言中所有的传参都是值传递(传值),都是一个副本,一个拷贝。

  • 值语义类型:参数传递的时候,就是值拷贝,这样就在函数中就无法修改原内容数据。

    • 基本类型:byte、int、bool、float32、float64、string等;
    • 复合类型:array、struct和指针等
  • 引用语义类型:参数传递的时候,也是值拷贝,不过是这样就可以修改原内容数据。

    • map、slice、chan和接口

引用类型值传递图解

下图以 slice 为例,说明引用类型的变量作为实参传递给函数形参时是值传递(拷贝):

在这里插入图片描述

在Go语言里,虽然只有传值,但是我们也可以修改原内容数据,因为参数是引用类型,在函数传递引用类型的变量时,会如上图进行值拷贝,拷贝的数据里有引用变量引用的数据的地址。

值语义类型的参数传递

package mainimport "fmt"func main() {var by byte = 123var i int64 = 10var boolean bool = falsevar f32 float32 = 3.14var f64 float64 = 3.1415926var str string = "hello world"fmt.Printf("mian 函数中的变量 by 的内存地址是 %p\n", &by)fmt.Printf("mian 函数中的变量 i 的内存地址是 %p\n", &i)fmt.Printf("mian 函数中的变量 boolean 的内存地址是 %p\n", &boolean)fmt.Printf("mian 函数中的变量 f32 的内存地址是 %p\n", &f32)fmt.Printf("mian 函数中的变量 f64 的内存地址是 %p\n", &f64)fmt.Printf("mian 函数中的变量 str 的内存地址是 %p\n", &str)fmt.Println("=======================函数调用前=============")callByValue(by, i, boolean, f32, f64, str)fmt.Println("=======================函数调用后=============")fmt.Printf("被调函数中修改形参的值,main 函数中打印结果为(不变): %v\n", by)fmt.Printf("被调函数中打印结果为:%v\n", i)fmt.Printf("被调函数中打印结果为:%v\n", boolean)fmt.Printf("被调函数中打印结果为:%v\n", f32)fmt.Printf("被调函数中打印结果为:%v\n", f64)fmt.Printf("被调函数中打印结果为:%v\n", str)
}func callByValue(by byte, i int64, boolean bool, f32 float32, f64 float64, str string) {fmt.Printf("被调函数中,形参的 by 内存地址是:%p\n", &by)fmt.Printf("被调函数中,形参的 i 内存地址是:%p\n", &i)fmt.Printf("被调函数中,形参的 boolean 内存地址是:%p\n", &boolean)fmt.Printf("被调函数中,形参的 f32 内存地址是:%p\n", &f32)fmt.Printf("被调函数中,形参的 f64 内存地址是:%p\n", &f64)fmt.Printf("被调函数中,形参的 str 内存地址是:%p\n", &str)by = 10i = 20boolean = truef32 = 13.14f64 = 13.146666str = "hello golang"
}
mian 函数中的变量 by 的内存地址是 0xc00010200a , 值为: 123
mian 函数中的变量 i 的内存地址是 0xc000102020 , 值为: 10
mian 函数中的变量 boolean 的内存地址是 0xc000102028 , 值为: false
mian 函数中的变量 f32 的内存地址是 0xc00010202c , 值为: 3.14
mian 函数中的变量 f64 的内存地址是 0xc000102030 , 值为: 3.1415926
mian 函数中的变量 str 的内存地址是 0xc000104140 , 值为: hello world
=======================函数调用前=============
被调函数中,形参的 by 内存地址是:0xc000102048 ,值为:123 
被调函数中,形参的 i 内存地址是:0xc000102050 ,值为:10 
被调函数中,形参的 boolean 内存地址是:0xc000102058 ,值为:false 
被调函数中,形参的 f32 内存地址是:0xc00010205c ,值为:3.14 
被调函数中,形参的 f64 内存地址是:0xc000102060 ,值为:3.1415926 
被调函数中,形参的 str 内存地址是:0xc000104160 ,值为:hello world 
=======================函数内部修改值=============
=======================函数调用后=============
被调函数中修改形参的值,main 函数中打印结果为(不变): 123
被调函数中打印结果为:10
被调函数中打印结果为:false
被调函数中打印结果为:3.14
被调函数中打印结果为:3.1415926
被调函数中打印结果为:hello world

从日志中可以发现:main 函数实参的地址和被调函数callByValue中形参的地址不同,在被调函数中修改形参的值并不会 影响实参变量的值。

指针类型

形参和实际参数内存地址不一样,证明是值传递。由于形参和实参是指针类型,指向同一个变量,函数内对指针指向变量的修改,会修改原内容数据。

package mainimport "fmt"func main() {var i int64 = 1fmt.Printf("main 函数中 i 内存地址是 %p\n", &i)     //0xc000104020 ip := &icallByPointer(ip)fmt.Printf("改动后的值是: %v\n", i)
}func callByPointer(ip *int64) { //这里定义的args就是形式参数fmt.Printf("callByPointer形参的内存地址是:%p\n", &ip) //0xc000108068fmt.Printf("callByPointer形参的值是:%p\n", ip)       //0xc000104020*ip = 10 //解引用
}
main 函数中 i 内存地址是 0xc000104020 
callByPointer形参的内存地址是:0xc000108068
callByPointer形参的值是:0xc000104020
改动后的值是: 10

引用语义类型变量的参数传递

package mainimport "fmt"func main() {//切片var s = make([]int64, 5, 10)s[0] = 1s[1] = 2s[2] = 3s[3] = 4s[4] = 5fmt.Printf("原始切片 len %v ,cap %v", len(s), cap(s))var p = &sfmt.Printf("原始切片   取地址(&s):%p ; \n直接对原始切片取地址( p):%p \n", &s, p)fmt.Printf("原始切片   底层数组的内存地址(s):     %p  \n原始切片   第一个元素的内存地址(&s[0]): %p\n", s, &s[0])callBySliceParam(s)fmt.Printf("改动后的值是: %v\n", s)
}func callBySliceParam(s1 []int64) {fmt.Printf("函数里,函数参数(切片)取地址 %p\n", &s1)fmt.Printf("函数里,函数参数(切片)的底层数组的内存地址是 %p \n", s1)fmt.Printf("函数里,函数参数(切片)第一个元素的内存地址: %p \n", &s1[0])s1[0] = 10
}
原始切片 len 5 ,cap 10原始切片   取地址(&s):0xc0001120a8 ; 
直接对原始切片取地址( p):0xc0001120a8 
原始切片   底层数组的内存地址(s):     0xc00012c000  
原始切片   第一个元素的内存地址(&s[0]): 0xc00012c000
函数里,函数参数(切片)取地址 0xc0001120d8
函数里,函数参数(切片)的底层数组的内存地址是 0xc00012c000 
函数里,函数参数(切片)第一个元素的内存地址: 0xc00012c000 
改动后的值是: [10 2 3 4 5]

通过输出日志,可以清楚地看到切片作为引用类型的特点:传递切片时,实际上是传递了切片的副本,但这个副本仍然指向同一个底层数组。因此,对切片的修改会影响到原始切片。

相关文章:

go函数传值是值传递?还是引用传递?slice案例加图解

先说下结论 Go语言中所有的传参都是值传递(传值),都是一个副本,一个拷贝。 值语义类型:参数传递的时候,就是值拷贝,这样就在函数中就无法修改原内容数据。 基本类型:byte、int、bool…...

PostgreSQL数据库笔记

PostgreSQL 是什么 PostgreSQL(简称Postgres或PG)是一个功能强大、可靠性高、可扩展性好的开源对象-关系数据库服务器(ORDBMS),它以加州大学伯克利分校计算机系开发的POSTGRES版本4.2为基础。 发展历程 起源与发展&a…...

财务软件源码SaaS云财务

在如今的商业环境中,准确的财务管理是一家企业取得成功的关键。然而,传统的财务管理方法已经无法满足现代企业的需求,需要一个全新的解决方案。推出了全新的财务软件为您提供完美的解决方案。 选择财务软件源码,您将享受到以下优…...

Elasticsearch集群和Kibana部署流程

搭建Elasticsearch集群 1. 进入Elasticsearch官网下载页面,下载Elasticsearch 在如下页面选择Elasticsearch版本,点击download按钮,进入下载页面 右键选择自己操作系统对应的版本,复制下载链接 然后通过wget命令下载Elastics…...

丹摩征文活动 | 丹摩智算:大数据治理的智慧引擎与实践探索

丹摩DAMODEL|让AI开发更简单!算力租赁上丹摩! 目录 一、引言 二、大数据治理的挑战与重要性 (一)数据质量问题 (二)数据安全威胁 (三)数据管理复杂性 三、丹摩智算…...

【Django】Clickjacking点击劫持攻击实现和防御措施

Clickjacking点击劫持 1、clickjacking攻击2、clickjacking攻击场景 1、clickjacking攻击 clickjacking攻击又称为点击劫持攻击,是一种在网页中将恶意代码等隐藏在看似无害的内容(如按钮)之下,并诱使用户点击的手段。 2、clickj…...

Ansys Zemax | 手机镜头设计 - 第 4 部分:用LS-DYNA进行冲击性能分析

该系列文章将讨论智能手机镜头模组设计的挑战,从概念和设计到制造和结构变形分析。本文是四部分系列中的第四部分,它涵盖了相机镜头的显式动态模拟,以及对光学性能的影响。使用Ansys Mechanical和LS-DYNA对相机在地板上的一系列冲击和弹跳过程…...

工具收集 - java-decompiler / jd-gui

工具收集 - java-decompiler / jd-gui 参考资料 用法:拖进来就行了 参考资料 https://github.com/java-decompiler/jd-gui 脚本之家:java反编译工具jd-gui使用详解...

《无线重构世界》射频模组演进

射频前端四大金刚 射频前端由PA、LNA、滤波器、开关“四大金刚” 不同的模块有自己的工艺和性能特点 分层设计 射频前端虽然只由PA、LNA、开关、混频器4个模块构成,但不同模块之间相互连接且相互影响。如果将射频系统当成一个整体来理解,其中的细节和…...

渗透测试---docker容器

声明:学习素材来自b站up【泷羽Sec】,侵删,若阅读过程中有相关方面的不足,还请指正,本文只做相关技术分享,切莫从事违法等相关行为,本人一律不承担一切后果 目录 一、Docker的作用与优势 二、docker的核心…...

【go从零单排】Atomic Counters原子计数

🌈Don’t worry , just coding! 内耗与overthinking只会削弱你的精力,虚度你的光阴,每天迈出一小步,回头时发现已经走了很远。 📗概念 在 Go 语言中,原子计数器(Atomic Counters)是…...

VSCode中python插件安装后无法调试

问题 VSCode中python插件安装后无法调试,如下,点击调试,VScode中不报错,也没有调试 解决方法 1、查看配置 打开所在路径 2、拷贝 将整个文件夹拷贝到vscode默认路径下 3、问题解决 再次调试,可以正常使用了…...

用react实现radio同时关联proform组件

实现&#xff1a; <ProFormRadio.GroupradioType{button}name{[bodyConfig, format]}label"请求体格式"initialValue{json}options{createTabs}fieldProps{{buttonStyle: solid,wrapperMarginInlineEnd: 20,onChange: e > {let v e.target.value;databaseMod…...

Objective-C 1.0和2.0有什么区别?

Objective-C ObjC比较小众&#xff0c;在1980年左右由Stepstone公司的Brad Cox和Tom Love发明。后来NeXT公司获得ObjC语言使用权&#xff0c;再后来到1996年NeXT被苹果公司收购也变成苹果公司使用&#xff0c;Mac市场占有率本身就不高&#xff0c;ObjC没有太多程序员。在移动互…...

TCP连接如何保障数据传输安全

TCP连接保障数据传输安全主要通过以下几个机制实现&#xff1a; 1、建立连接&#xff1a;TCP通过三次握手过程建立连接&#xff0c;确保通信双方实体真实存在&#xff0c;为后续的可靠数据传输打下基础。 2、序号机制&#xff1a;TCP为每个传输的数据包分配一个序号&#xff…...

【论文复现】ChatGPT多模态命名实体识别

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀ChatGPT ChatGPT辅助细化知识增强&#xff01;1. 研究背景2. 模型结构和代码3. 任务流程第一阶段&#xff1a;辅助精炼知识启发式生成第二阶段…...

管理 Elasticsearch 变得更容易了,非常容易!

作者&#xff1a;来自 Elastic Ken Exner Elasticsearch 用户&#xff0c;我们听到了你的心声。管理 Elasticsearch 有时会变得很复杂&#xff0c;面临的挑战包括性能调整、问题检测和资源优化。我们一直致力于简化你的体验。今天&#xff0c;我们宣布了自收购 Opster 以来的一…...

SynchronousQueueworkQueue.offer() 和 poll() 方法的超时控制及线程池的讨论

2024.11.12 11:26 问&#xff1a;workQueue.offer(command) 这里 workQueue.poll(keepAlive, TimeUnit.NANOSECONDS) : 这里的 workQueue.offer(command) 没有超时时间控制&#xff1f; Claude 3.5 Haiku 非常好的问题&#xff01;我来详细解释 offer() 和 poll() 方法的区别…...

自动驾驶---“火热的”时空联合规划

1 背景 早期的不少规划算法都是横纵分离的(比如Apollo),先求解path之后,依赖path的结果再进行speed的求解。这种横纵解耦的规划方式具有以下特点: 相对较为简单,计算量通常较小,容易实现实时性要求。但是由于分别规划横向和纵向运动,可能会忽略两者之间的耦合关系,导致…...

命令行工具进阶指南

&#x1f680; 命令行工具进阶指南&#xff1a;Git、Shell与效率工具的进阶之路 掌握命令行工具&#xff0c;让你的开发效率突飞猛进。本文将深入探讨 Git 高级技巧、Shell 脚本自动化以及各种效率倍增的 CLI 工具。 &#x1f4d1; 目录 Git 高级技巧与工作流Shell 脚本自动化…...

React Native 导航系统实战(React Navigation)

导航系统实战&#xff08;React Navigation&#xff09; React Navigation 是 React Native 应用中最常用的导航库之一&#xff0c;它提供了多种导航模式&#xff0c;如堆栈导航&#xff08;Stack Navigator&#xff09;、标签导航&#xff08;Tab Navigator&#xff09;和抽屉…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

2023赣州旅游投资集团

单选题 1.“不登高山&#xff0c;不知天之高也&#xff1b;不临深溪&#xff0c;不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案

这个问题我看其他博主也写了&#xff0c;要么要会员、要么写的乱七八糟。这里我整理一下&#xff0c;把问题说清楚并且给出代码&#xff0c;拿去用就行&#xff0c;照着葫芦画瓢。 问题 在继承QWebEngineView后&#xff0c;重写mousePressEvent或event函数无法捕获鼠标按下事…...

【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题

【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要&#xff1a; 近期&#xff0c;在使用较新版本的OpenSSH客户端连接老旧SSH服务器时&#xff0c;会遇到 "no matching key exchange method found"​, "n…...

【JVM面试篇】高频八股汇总——类加载和类加载器

目录 1. 讲一下类加载过程&#xff1f; 2. Java创建对象的过程&#xff1f; 3. 对象的生命周期&#xff1f; 4. 类加载器有哪些&#xff1f; 5. 双亲委派模型的作用&#xff08;好处&#xff09;&#xff1f; 6. 讲一下类的加载和双亲委派原则&#xff1f; 7. 双亲委派模…...

Python Einops库:深度学习中的张量操作革命

Einops&#xff08;爱因斯坦操作库&#xff09;就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库&#xff0c;用类似自然语言的表达式替代了晦涩的API调用&#xff0c;彻底改变了深度学习工程…...

LOOI机器人的技术实现解析:从手势识别到边缘检测

LOOI机器人作为一款创新的AI硬件产品&#xff0c;通过将智能手机转变为具有情感交互能力的桌面机器人&#xff0c;展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家&#xff0c;我将全面解析LOOI的技术实现架构&#xff0c;特别是其手势识别、物体识别和环境…...

上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式

简介 在我的 QT/C 开发工作中&#xff0c;合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式&#xff1a;工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...

消防一体化安全管控平台:构建消防“一张图”和APP统一管理

在城市的某个角落&#xff0c;一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延&#xff0c;滚滚浓烟弥漫开来&#xff0c;周围群众的生命财产安全受到严重威胁。就在这千钧一发之际&#xff0c;消防救援队伍迅速行动&#xff0c;而豪越科技消防一体化安全管控平台构建的消防“…...