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]

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

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

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

相关文章

穿越时空的全球时钟:一个实时多时区显示的网页应用

引言 在当今这个全球化时代,人们经常需要与世界各地的朋友、同事或客户进行沟通。然而,由于时差的存在,找到一个合适的沟通时间往往成为一大挑战。为了解决这一问题,我们开发了一个名为“全球时钟”的网页应用,它能够…

本地部署免费开源助手Ollama

Ollama 安装 安装ollama 官方网站:https://ollama.com/download 2. 安装成功 3. 运行模型 模型:https://ollama.com/library 运行: ollama run llama3.2:3b Mac 、Linux 版本安装类似。 Open-WebUI界面安装 openwebui官网:http…

three.js杂记

空间 - 位置变换: // 假设有一个Three.js的对象: object3D // 存储矩阵位置 const matrix object3D.matrix.clone(); const matrixArray matrix.toArray(); // 转换为数组 // 之后,当你需要恢复位置时 object3D.matrix.fromArray(matrixArray); …

通过DNS服务器架构解释DNS请求过程

在前面的章节,这里,基于PCAP数据包和RFC文档详细介绍了DNS请求和响应的每个字段的含义。但是在现实的网络世界中,DNS请求和响应的数据包是怎么流动的,会经过哪些设备。本文将着重说明一下目前网络空间中DNS请求和响应的流动过程。 当前网络空间中比较常见DNS请求的流程如下…

HBase使用create创建表时报错ERROR: KeeperErrorCode = NoNode for /hbase/master

场景模拟 1. 正常情况 模拟ERROR: KeeperErrorCode NoNode for /hbase/master错误场景。 正常情况下创建hbase表如下图所示。 2. 删除hbase集群的zk节点 进入zookeeper客户端。 zkCli.sh删除hbase的zk节点。 deleteall /hbase退出zookeeper客户端。 quit3. 重启hbase集…

软件分享丨火绒应用商店

【资源分享】 资源名:火绒应用商店 官方网址:点击跳转 火绒应用商店是由火绒安全推出的一款独立软件。它提供了海量的应用程序,涵盖办公、社交、游戏、视频、工具等多种领域和类别,方便用户轻松找到所需的应用并进行一键下载安装…

在线考试系统demo页面

<!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>在线考试系统</title><link rel"styl…

从0到1基于LangChain制作一个AI猫娘

前言&#xff1a; 看到B站上的AIVtuber的项目落地了&#xff0c;就心血来潮想制作一个AI的猫娘供自己使用&#xff0c;顺便出一个简单的教程&#xff0c;跳过理论&#xff0c;直接实践&#xff0c;作者也还在学习摸索中&#xff0c;所以有错误可以直接在评论区指正。&#xff0…

前端---高效工具(一) : NVM的使用

一、NVM用途 方便快捷 管理和切换各个 node版本。现在前端项目Vue2与Vue3很多项目要求的node版本不一致导致的。 二、安装 如果有安装nodejs&#xff0c;按一下步骤清理环境 1.卸载应用程序的 nodejs 2.删除环境变量中nodejs的配置 3.删除C:\Users\Administrator 中最下面…

反序列化漏洞浅析

Apache InLong 是开源的高性能数据集成框架&#xff0c;支持数据接入、数据同步和数据订阅&#xff0c;同时支持批处理和流处理&#xff0c;方便业务构建基于流式的数据分析、建模和应用。浅析Apache InLong < 1.12.0 JDBC反序列化漏洞&#xff08;CVE-2024-26579&#xff0…

三周精通FastAPI:39 用FastAPI CLI命令行程序管理FastAPI项目

官方文档&#xff1a;https://fastapi.tiangolo.com/zh/fastapi-cli/ FastAPI CLI FastAPI CLI 是一个命令行程序&#xff0c;你可以用它来部署和运行你的 FastAPI 应用程序&#xff0c;管理你的 FastAPI 项目&#xff0c;等等。 当你安装 FastAPI 时&#xff08;例如使用 p…

Bean实例化

Bean有3种实例化方法 1.通过无参构造方法实例化 假如我们有以下结构&#xff1a; 这里我们在无参构造方法种打印字符串&#xff1a; 然后我们运行 可知&#xff0c;IoC管理bean进行实例化的时候是通过无参构造方法实例化的。 2.静态工厂实例化 假设我们有以下配置文件&…

【网络安全】线程安全分析及List遍历

未经许可,不得转载。 文章目录 线程线程安全问题遍历List的方式方式一方式二方式三方式四(Java 8)方式五(Java 8 Lambda)遍历List的同时操作ListVector是线程安全的?使用线程安全的CopyOnWriteArrayList使用线程安全的List.forEach线程 线程是程序执行的最小单位。一个程…

ReactPress 安装指南:从 MySQL 安装到项目启动

ReactPress Github项目地址&#xff1a;https://github.com/fecommunity/reactpress 欢迎Star。 ReactPress 是一个基于 React 的开源发布平台&#xff0c;适用于搭建博客、网站或内容管理系统&#xff08;CMS&#xff09;。本文将详细介绍如何安装 ReactPress&#xff0c;包括…

caozha-whois(域名Whois查询源码)

caozha-whois&#xff0c;是一个采用原生PHP写的域名Whois查询模块&#xff0c;支持全球大部分域名的whois查询&#xff0c;支持中文域名在内的多种域名后缀&#xff0c;包括&#xff1a;.com&#xff0c;.net&#xff0c;.cn&#xff0c;.com.cn&#xff0c;.org&#xff0c;.…

2024 年(第 7 届)“泰迪杯”数据分析技能赛A 题 自动化生产线数据分析 完整代码结果分享

一、背景 随着信息技术的快速发展&#xff0c;工业自动化领域的智能控制系统日益完善。自动化生产线能够独立完成从物料输送到元件抓取&#xff0c;再到产品安装和质量检验的各个环节&#xff0c;这不仅极大提升了制造效率和产品质量&#xff0c;也有效降低了生产成本。 为了使…

探索Python自动化新境界:Invoke库的神秘面纱

文章目录 **探索Python自动化新境界&#xff1a;Invoke库的神秘面纱**第一部分&#xff1a;背景介绍第二部分&#xff1a;Invoke库是什么&#xff1f;第三部分&#xff1a;如何安装Invoke库&#xff1f;第四部分&#xff1a;Invoke库函数使用方法1. 定义任务2. 执行任务3. 任务…

Qt_day4_Qt_UI设计

目录 Qt_UI设计 1. Designer 设计师&#xff08;掌握&#xff09; 2. Layout 布局&#xff08;重点&#xff09; 2.1 基本使用 2.2 高级用法 2.3 代码布局&#xff08;了解&#xff09; 3. Designer与C的关系&#xff08;熟悉&#xff09; 4. 基本组件&#xff08;掌握…

conda和conda的常用命令

目录 一、什么是conda 1. conda的定义和作用 2. conda的特点 3. conda与pip的区别 二、conda的常用命令 1. 环境管理 2.包管理 3. 查看信息 4. 清理和维护 5. 频道(channel)管理 6. 导出和复制环境 7. 加速相关(镜像) 一、什么是conda 1. conda的定义和作用 2. co…

基于STM32通过TM1637驱动4位数码管详细解析(可直接移植使用)

目录 1. 单位数码管概述 2. 对应编码 2.1 共阳数码管 2.2 共阴数码管 3. TM1637驱动数码管 3.1 工作原理 3.1.1 读键扫数据 3.1.2 显示器寄存器地址和显示模式 3.2 时序 3.2.1 指令数据传输过程&#xff08;读案件数据时序&#xff09; 3.2.2 写SRAM数据…