Go中都是值传递

【12】深入理解Golang值传递与引用传递:避坑指南与性能优化 深入理解Golang值传递与引用传递:避坑指南与性能优化 阅读详情

聊聊后端面试那些事

原文

Go中都是值传递-【公粽号:堆栈future】

我看在技术大群里面有人问我,到底值类型,引用类型以及指针类型有什么区别?为什么别人说函数传参是引用传递或者值传递,有的人说是指针传递?

想要彻底搞清楚这个问题,你得先通过表现来理解一下,然后在深入源码理解下你很快就会明白的。

所以网上说的有可能都是错误的,大家千万别被误导!

我们接下来重点解决函数传递参数到底是值传递还是其他类型传递!

三者区别
  • 值类型 就是变量赋值的时候将直接获得一个真实的数据副本,请大家再次看清楚,真实的"数据"副本。比如var int a = 10,b:=a 这就相当于a持有10,b持有a的数据的副本 那就将10拷贝到b指向的内存。

  • 引用类型 就是仅仅是把对象的引用赋给变量,这样就可能导致多个变量引用到一个实际对象实例上。比如a := make([]int, 0),b:=a[2:],那么a和b持有的就是底层对象的引用,说白了a和b就是底层对象的别名。

  • 指针类型 就是赋给变量的是一个内存地址,这个地址指向真实的数据,比如var int a = 10,p:=&a,这个p就是指针变量,它存储的就是a的地址。

注意:在Go中弱化了指针,所以一般只需要关注值和引用类型就可以。

函数传参

首先声明一点:在Go中除了slice,map,channel类型之外的变量都是值类型。

那就好说了,引用类型就三种:slice, map和channel,其他都是值类型。

在Go中引用类型的变量初始化默认是make,但是new也是可以的,比如:

package main

import "fmt"

type A []int 

func main() {
 a := new(A)
 *a = append(*a, 1)
 fmt.Println(*a) //[1]

 a1 := make([]int, 0)
 a1 = append(a1, 1)
 fmt.Println(a1) //[1]
}

当然map以及channel也是可以用make和new的,大家下去试试哈。

至于make和new的区别大家下去自己看哈,这不是本文的重点。

接下来我们重点来聊聊函数传参的问题,我们都知道值传递是copy一份,所以这个大家都能理解,我们重点讲解大家疑惑的问题,引用类型的传参问题。

首先大家看一个例子,即看看它的表现是什么:

package main

import "fmt"

func CopyList(a []int)  {
 a = append(a, 2)
 fmt.Printf("copylist is %p \n", &a)
 fmt.Println("copylist value is ", a)
}
func main() {
 a := make([]int, 0)
 a = append(a, 1)
 fmt.Println("main value is ", a)
 fmt.Printf("main address is %p \n", &a)
 CopyList(a)
}

输出:
main value is  [1]
main address is 0xc0000a6018 

copylist is 0xc0000a6048 
copylist value is  [1 2]

我们通过结果分析下引用传递会有什么影响。

  1. 首先函数参数是a []int

  2. main中定义的引用类型变量是a并且也做了初始化

  3. 然后调用CopyList(a)

  4. 看在main中a的地址和在CopyList中a的地址,发现不一样?为什么不一样呢?因为Go语言在设计的时候明确表示函数参数传递是值传递,所以相当于函数CopyList拷贝了一份变量,这个时候次a非比a。但是那你可能说:为什么拷贝了一份,但是从结果来看就是引用啊,因为函数CopyList改变了外面main中a的值。

答案就是Go在设计引用类型的时候,比如这三者map,slice和channel,他们的结构体中并没有直接保存数据,而是保存了指向数据的指针,那么在函数中传递这三种的变量其实只是拷贝了一份它们自己的一份结构体,但是结构体里面具体保存的指针指向的地址还是同一份,没有变化的。所以这也就说明函数中为什么可以改变引用类型变量的值了,因为底层指针指向的地址是同一个。

分析完了slice,其它两个都比较简单,这里就不再演示了,大家下去自己尝试。

图片

type slice struct {
 array unsafe.Pointer //指针 到时候slice初始化的时候会用mallocgc分配内存,把这块内存地址保存到array中。
 len   int
 cap   int
}

map和channel里面也是有指针,指向一块内存空间。

小结

大家一定要记住在Go中函数传递参数一定是值传递,千万别搞混淆了,至于为什么上面也说清楚了,如果大家还不懂就进群,大牛比较多为你继续解惑哈。

- END -

堆栈future

使很多处于迷茫阶段的coder能从这里找到光明,堆栈创世,功在当代,利在千秋

图片

中国1986-2024年30米分辨率年最大NDVI数据集:条带修复技术与植被动态监测 本文介绍了中国1986-2024年30米分辨率年最大NDVI数据集的构建,重点阐述了针对Landsat 7 SLC-off故障等问题的条带修复技术。通过应用GapFill等核心算法,该数据集有效修复了数据缺失,为长时间序列的植被动态监测、生态变迁分析和极端气候事件评估提供了高质量、连续可靠的数据基础。 阅读详情

相关推荐

FitzHugh-Nagumo 模型连续-MATLAB仿真

【代码】FitzHugh-Nagumo 模型连续-MATLAB仿真。

qq_43688618的博客 882

面试官:Go函数参数传递到底是值传递还是引用传递?

大家好,我是木川在函数中,如果参数是非引用类型(int、string、struct等这些),这样就在函数中就无法修改原内容数据;如果参数是引用类型(指针、map、slice、chan等这些),这样就可以修改原内容数据。是否可以修改原内容数据,和传值、传引用没有必然的关系。在C++中,传引用肯定是可以修改原内容数据的,在Go语言里,虽然只有传值,但是我们也可以修改原内容数据,因为参数是引用类型先说下...

木川的技术之路 803

FOC:【1】浅析SVPWM算法(七段式)以及MATLAB仿真验证

最近的科研项目需要使用到SVPWM算法,网上相关的原理介绍很多。对于纯应用的需求来说,或许有些内容上的冗余。 本文的目的就是简要并且明确的给出具体的计算步骤,可以帮助快速上手。同时利用MATLAB进行了简单算法验证。.....................

Alex的技术博客 1万+

为什么说golang参数传递为值传递?

一、函数参数传递方式 函数参数传递有2种方式:值传递和引用传递。 值传递是指调用函数时将参数值复制一份到函数,如果对函数参数进行修改,影响不到实际参数。 引用传递是指调用函数时将参数的指针传递到函数中,函数中对参数的修改,将影响到实际参数。 不同编程语言的函数参数传递方式不尽相同,例如C语言中的int、float等参数类型采用值传递的方式,而数组类型默认为引用传递,C++中的引用传递显而易见,其类型系统直接包含了引用类型。 二、Go语言中的函数传递方式 那么Go语言何种参数传递方式呢?开门见山,直接上官方说

u011952832的博客 1021

C#菜鸟教程学习笔记

C#菜鸟教程学习笔记 C#简介 C# 是一种编程语言,它是由微软开发的。 C# 编程是基于 C 和 C++ 编程语言的,它与 Java 也非常相似。 C# 是 .Net 框架的一部分,且用于编写 .Net 应用程序。 .Net 框架(.Net Framework)能编写出下面类型的应用程序: ①Windows 应用程序 ②Web 应用程序 ③Web 服务 常用的C# 编程的开发工具:Visual Studio(VS:可视化工作室) C#程序结构 一个 C# 程序(C# 文件的后缀为 .cs)主要包括以下部分

mlc_WTMOTW的博客 4977

PCL 平面点云的凹多边形边界提取【2025最新版】

平面点云的凹多边形边界提取及边界轮廓线绘制。博客长期更新,本文最近更新时间为:2025年1月6日。

点云侠的博客 7183

Golang 中直接赋值,是值传递还是地址传递?

1. 普通变量 普通变量都是值传递 a := 1 b := a fmt.Printf("%p\n%p", &a, &b) // 0xc0000160a8 // 0xc0000160c0 a := 1.0 b := a fmt.Printf("%p\n%p", &a, &b) // 0xc0000160a8 // 0xc0000160c0 a := "hello" b := a fmt.Printf("%p\n%p", &a, &b

qq_15267283的博客 1万+

软考高级信息系统项目管理师系列论文之:百篇软考高级信息系统项目管理师论文范文

软考高级信息系统项目管理师系列论文之:百篇软考高级信息系统项目管理师论文范文

zhengzaifeidelushang的博客 3579

【golang学习笔记】Go语言中参数的传递是值传递还是引用传递

Go中所有的参数传递都是值传递,是对数据进行一个拷贝。具体分为引用类型和非引用类型非引用类型(值类型)int,string,float,bool,数组和struct;特点值类型变量声明后,直接存的就是对应的数据。引用类型指针,slice,map,channel,接口,函数等。特点变量存放的是一个内存地址值,这个地址值指向的空间存的才是最终的值。内存通常在堆中分配,当没有任务变量引用这个地址时,该地址对应的数据空间就成为一个垃圾,通过GC回收。...

热爱编程的菜鸟 1740

uniapp - 强力解决H5网页浏览器跨域问题,如何解决uniapp请求接口在浏览器跨域问题,UniApp H5 跨域代理配置详细教程完美解决所有uniapp跨域(调用第三方接口或服务器api跨域)

uni-app 跨域,uniApp解决h5跨域问题,解决uni-app请求接口在浏览器跨域问题,uni.request请求跨域问题解决方案,uni-app-跨域解决方法,彻底解决uniapp发布为H5的跨域问题,uniapp H5页面设置跨域请求_uniapp h5跨域配置,uniapp开发 H5 解决跨域问题,uniApp请求解决跨域问题,uniapp request如何实现前端请求跨域,解决uniapp调试过程中的请求跨域和环境配置,Uniapp调用外部api接口跨域请求,uni-app发布H5页面跨域

🏆 前端领域优质创作者 5354

71.qt quick-可伸展菜单-抽屉栏示例 通用QML界面(一键换肤)

特点: 支持动态添加item、删除item、自适应界面 附带添加删除、展开等动画 同时支持qwidget、qml加载 支持number提示(比如消息数量等) 侧边抽屉栏支持动画伸展 支持换肤、拖拽、最大化等

抵抗时间扭曲,坚持做一件有意义的事 5285

go的参数传递都是值传递,但切片需要注意

根据之前学习python和java的经验,每次学习一门新语言时,一定要搞清楚方法的参数传递是值传递,引用传递还是指针传递。主要原因就是需要知道,某种类型的数据传递给某个方法后,方法里面对它的修改是否会影响到这个数据本身。

xzc的博客 751

基于Cesium实现,动态水面+大坝排水动画

一、绘制面状水域,使用水波纹理,进行渲染,水体透明,可以看到底色。三、使用粒子系统,将喷泉改变方向,加上重力设置,实现排水动画。二、绘制线状三维体,用作模拟大坝拦截效果。四、最后,模拟水位上升,进行淹没分析,

一醉千秋的专栏 1418

Golang中的值传递

首先为什么讨论这个基础的问题,因为博主今天在写代码的时候又遇到了这个基础的问题,之前也遇到过,但是没有记录,所以又忘记了,还是那句话好记性不如烂笔头,记录下来。 问题是这样的,我要去修改内存中的map里头的数据,发现改了怎么也没生效,于是写了个demo验证 package main import ( "fmt" ) func main() { clothesMap := map[int]Clothes{ 1:{ "Nike", 300, }, 2:{ "Adidas"

weixin_42957200的博客 1684

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Go函数传参:值传递&用明白Go的指针

Golang函数传参:值传递 不杠哦,Go语言里面就是没有引用传递 先拿C语言说话,解释一下值传递、指针传递和引用传递的含义 值传递: 形参是实参的拷贝,改变形参的值并不会影响外部实参的值,是将实参的值拷贝到另外的内存地址中才修改。从被调用函数的角度来说,值传递是单向的(实参->形参),参数的值只能传入,不能传出。当函数内部需要修改参数,并且不希望这个改变影响调用者时,采用值传递。 指针传递: 形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作;指针传递参数本质上是值传递的方

qq_39618369的博客 7598

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Go语言 值传递

1.GO中只有值传递,没有引用传递2.如果需要函数内部的修改能影响到函数外部,那就传指针3.map/chan本身就是指针,是引用类型的,直接传其本身即可4.slice 在传递过程中,本质上传递的是其本身的内存地址 array,也即是指针,直接传slice本身即可5.slice的append操作需要修改结构体的len或者cap,类似于struct。如果需要传递到函数外部,需要传指针,或者通过函数返回值返回结果。

m0_57408211的博客 1525

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

go语言传参是值传递还是引用传递

曾经在某次go面试中被面试官问到:“go中引用类型有哪些?”,我答到:“slice,map,channel”,面试官:“其实go没有引用类型,都是值类型“,当时我就懵了,这么基础的问题居然我跟面试官意见不同。现在想想也许是我听错了,他应该说的是:”go没有引用传递,都是值传递“。我们今天就来聊一下这个话题。 一个简单的例子 funcmodifySlice(slice[]int){ slice[0] = 11}funcmain(){mySlice:=[]int{1,2,3} m...

taoerchun的专栏 2433

golang中数组是值传递_GoLang中按值传递的值

golang中数组是值传递 现在,我们进入了一些核心概念! 众所周知,了解Go程序对机器的影响非常重要。 无论您通过什么,一切都将在Go中通过价值传递。 你所看到的就是你得到的。 每个go例程(即执行路径)都将获得Stack,这是一个连续的内存。 Go例程需要堆栈来完成所需的所有分配。 稍后我们将学习go例程,它就像一个线程,但更加轻巧。 当go例程执行一个函数时,它将开始从分配的...

danpu0978的博客 938

Golang中的值传递和引用传递

本文将深入探讨Golang中的值传递和引用传递,并解释它们在编程中的应用和区别。通过值传递,我们可以确保函数或方法对参数的修改不会影响原始值。值传递是指在函数或方法调用时,将实际参数的值复制一份传递给被调用函数或方法的形式参数。引用传递是指在函数或方法调用时,将实际参数的地址传递给被调用函数或方法的形式参数。在理解值传递和引用传递之前,我们需要了解变量在内存中的存储方式。值传递适用于需要在函数或方法中对参数进行修改时不影响原始值的情况。引用传递适用于需要在函数或方法中对参数进行修改时影响原始值的情况。

all_about_WZY的博客 2188

【GO】 1.Go的参数传递都是值传递

在 Golang 中函数之间传递变量时总是以值的方式传递的,无论是 int,string,bool,array 这样的内置类型(或者说原始的类型),还是 slice,channel,map 这样的引用类型,在函数间传递变量时,都是以值的方式传递,也就是说传递的都是值的副本。 1.int类型值传递的代码示例: package main import ( "fmt" ) func m...

chen_peng7的博客 1461

GoLang之值传递、引用传递

GoLang之值传递、引用传递

weixin_52690231的博客 1748

Go 的值传递与引用传递

在说 Go 的 与 之前需要先了解一下 Go 的传递方式。首先,Go 的变量有 与 两种类型,某种意义上来说这两种参数传递的方式都是按值传递。为什么这么说呢?当一个变量被声明为 类型。将其作为参数传递时,传递的是变量的副本。你会发现它的内存地址以及引用内存地址与原变量都是不一样的。如果变量被声明为 类型。传递变量时,会创建一个新的指针,同时这个指针会指向原变量的内存地址。所以这种传递方式可以看作是传递了一份变量引用地址的副本。这就是为什么前面说 Go 的参数传递都是按值传递。...

Leor的博客 2551

go中的值传递和指针传递

比如向函数调用栈里的下一个方法传递对象A,二者的区别在于,指针传递,传的是对象A的内存地址,传的是一个小巧的地址。值传递,是复制对象A的数据传下去。之前有个说法:想在调用的函数内部改变对象A的值,就用指针传递,但这句话也不全对,因为用值传递,照样可以实现同样的效果。最后,如果传递的是一个很大的结构体,那用指针传递更优。),它们占用的内存大小固定且小,大小与指针大小相当。值传递,代表的意志是:函数收到的是一个副本数据,这两种实现方式,在此时,没有谁优谁劣。注意看二者的返回值,对于固定大小的类型(

llg___的博客 1610

Go语法:引用/值传递

结构体传递地址时,可修改结构体(包括多层嵌套),但存在差异:字段为引用类型:本身存地址,修改字段指向的数据会影响原始值;若重新创建整个元素并赋值,仅改变当前引用指向,原始引用不变。字段为值类型:修改的是元素本身的值,会直接改变原始结构体的字段值。结构体字段若为非引用类型,赋值时传递的是副本,对副本的修改不影响原始字段。for range 循环中,迭代变量是集合元素的副本(类似函数传参的值传递),修改迭代变量不影响原始集合。

LanJieZhiFu的博客 1022

Golang: 值传递还是引用传递

本部分引用 Go 官方 FAQ 的 “When are function parameters passed by value?”,内容如下。如同 C 系列的所有语言一样,Go 语言中的所有东西都是以值传递的。也就是说,一个函数总是得到一个被传递的东西的副本,就像有一个赋值语句将值赋给参数一样。传值的意思是:函数传递的总是原来这个东西的一个副本,一副拷贝。其指的是在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。

Ch3nnn的博客 801

GoLang中按值传递的值

现在,我们进入了一些核心概念! 众所周知,了解Go程序对机器的影响非常重要。 无论您通过了什么,一切都在Go中通过价值传递。 你所看到的就是你得到的。 每个go例程(即执行路径)都将获得Stack,这是一个连续的内存。 Go例程需要堆栈来完成所需的所有分配。 稍后我们将学习go例程,它就像一个线程,但更轻巧。 当go例程执行一个函数时,它将开始从分配的堆栈中获取一部分或一部分内存...

danpu0978的博客 313
上一篇: 服务稳定性SLA-2015年阿里双十一惨痛的教训
下一篇: k8s两种部署架构,你们是哪一种?为什么面试官会问你你们怎么部署微服务的呢?
stackfuture
博客等级 码龄5年 23粉丝 38原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值