问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

面试官问:Go中的参数传递是值传递还是引用传递?

发布网友 发布时间:2024-10-01 08:22

我来回答

1个回答

热心网友 时间:2024-11-03 13:39

一个程序中,变量分为变量名和变量内容,变量内容的存储一般会被分配到堆和栈上。而在Go语言中有两种传递变量的方式值传递和引用传递。其中值传递会直接将变量内容附在变量名上传递,而引用传递会将变量内容的地址附在变量名上传递。

Golang中是如何做到

如果在面试时有面试官提问你:“Go的参数是如何传递的?”你会怎么回答呢?

这个问题其实只有一个答案。因为在Golang中所有的类型传递都是通过值传递实现的,而不是引用传递,即使是指针的传递也是通过copy指针的方式进行。另外对于一些包裹了底层数据的数据结构,其值传递的过程中,复制的也只是实例的指针,而不是底层数据所暴露出来的指针。

下面以Go版本1.8的slice为例来简单了解一下:

funcmakeslice(et*_type,len,capint)unsafe.Pointer{mem,overflow:=math.MulUintptr(et.size,uintptr(cap))ifoverflow||mem>maxAlloc||len<0||len>cap{//NOTE:Procea'lenoutofrange'errorinsteadofa//'capoutofrange'errorwhensomeonedoesmake([]T,bignumber).//'capoutofrange'istruetoo,butsincethecapisonlybeing//suppliedimplicitly,sayinglenisclearer.//Seegolang.org/issue/4085.mem,overflow:=math.MulUintptr(et.size,uintptr(len))ifoverflow||mem>maxAlloc||len<0{panicmakeslicelen()}panicmakeslicecap()}returnmallocgc(mem,et,true)//申请内存}

可以看到slice在初始化的过程中调用了runtime中的makeslice函数,这个函数会将slice的地址返回给接受的变量。

typeslicestruct{arrayunsafe.Pointer//底层数组的地址lenintcapint}//初始化过程p:=make([]int,0)fmt.Printf("变量p的地址%p",&p)fmt.Printf("slice的地址%p\n",p)

上面打印时出现的是的内容,这是因为Go内部实现了自动解引用(即Go内部实现的解引用操作)。自动解引用时receive会从指针类型转变为值类型。顺带一提自动取引用时receiver会从值类型转变为指针类型。

如果未实现自动解引用时会怎样呢?下面是未实现自动解引用的情况:

//当我们打印变量p的时候,实际过程是发生了这样的变化//只是猜测,当然发生解引用是一定的//&取地址操作符//*根据地址取值操作也称之为解引用运算法,间址运算符//1.获取指针地址&p//2.获取array的地址&((&p).array)//3.获取底层数组实际内容*&((&p).array)

未实现自动借用的函数传递过程,也是通过复制指针的方式来传递的,内容如下:

packagemainimport("fmt")funcchange(p1[]int){fmt.Printf("p1的内存地址是:%p\n",&p1)//p1的内存地址是:0xc0000a6048fmt.Printf("函数里接收到slice的内存地址是:%p\n",p1)//函数里接收到slice的内存地址是:0xc00008c030p1=append(p1,30)}funcmain(){p:=make([]int,3)//抛出一个指针p=append(p,20)fmt.Printf("p的内存地址是:%p\n",&p)//p的内存地址是:0xc00009a018fmt.Printf("slice的内存地址是:%p\n",p)//slice的内存地址是:0xc00008c030change(p)//重新生成一份地址p1指向slice地址fmt.Printf("修改之后p的内存地址%p\n",&p)//修改之后p的内存地址0xc00009a018fmt.Printf("修改之后slice的内存地址%p\n",p)//修改之后slice的内存地址0xc00008c030fmt.Println("修改之后的slice:",p)//修改之后的slice[00020]fmt.Println(*&p)//[00020]}

需要注意的是,在函数传递的过程中copy的不是slice内部指向底层数组的指针,而是在makeslice函数所返回的指针。

源码实现

大家在看一些老旧的文章的时候,可能看到过这样的说法:make返回的是slice的实例。但其实这种说法已经过时了,在Golang1.2版本之后make返回的就是实例的指针。

githubpr地址:https://github.com/golang/go/commits/dev.boringcrypto.go1.12/src/runtime/slice.go

扩展

其实和slice类似的还有map,chan。

先说map,map的官网定义:“Goprovidesabuilt-inmaptypethatimplementsahashtable.Maptypesarereferencetypes,likepointersorslices.”而chan和map一样也是一个指针,也就是说二者和slice的原理相似。

funcmakemap(t*maptype,hintint,h*hmap)*hmap{mem,overflow:=math.MulUintptr(uintptr(hint),t.bucket.size)ifoverflow||mem>maxAlloc{hint=0}...}funcmakechan(t*chantype,sizeint)*hchan{...mem,overflow:=math.MulUintptr(elem.size,uintptr(size))ifoverflow||mem>maxAlloc-hchanSize||size<0{panic(plainError("makechan:sizeoutofrange"))}...}

如果平时的使用中不注意,会出现一些不必要的麻烦,如:

packagemainimport"fmt"typeInfoInsstruct{Namestringinfo[]string}funcNewInfoIns()InfoIns{returnInfoIns{Name:"",info:nil,}}func(n*InfoIns)SetInfo(info[]string){n.info=info}funcmain(){infoIns:=NewInfoIns()info:=[]string{"p1","p2","p3"}infoIns.SetInfo(info)info[1]="p4"fmt.Println(infoIns.info)//[p1p4p3]}

这里的InfoIns在SetInfo之后存的是info的地址。一旦info在后续有改动InfoIns中的内容也随之会被改动。解决的方法是在SetInfo的时候重新申请一份地址。

func(n*InfoIns)SetInfo(info[]string){n.info=make([]string,len(info))copy(n.info,info)}脚注

借助Goland查看Go源码的方式:Ctrl+Shift+f全局搜索,选择Scope中的ALLPlace。

推荐阅读

一文聊透IP地址的那些事

Golang常见设计模式之装饰模式

原文:https://juejin.cn/post/7099268340513767461
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
法律规定毒品数量达到多少克可以判死刑呢? 总练名实的近义词 水文数据处理的工作内容不包括( )。 如何解除冻结微信账户? 如何解除微信号被冻结状态? 派克钢笔,想换细笔尖,自己有笔尖,但是不会换,笔尖处有方孔!求答案_百... ...然后吃饭的时候我碗里还有一大块排骨没吃完,男友当着舍友面夹走排 ... os版型啥意思os版型介绍 包庇罪量刑标准是怎样的 多次催收无果最后起诉了担保人,担保人应如何自保? 康佳电视黑屏了怎么恢复? 吃什么可以消化排便 It is essential/important/imperative/obligatory/necessary/mandatory... 如何控制好卤肉的时间和火候 卤肉怎么做味道更棒? 卤菜制作应该注意的一些问题和细节 五香卤牛肉在制作中有哪些常见的误区需要避免? 用电饭锅自制卤肉有哪些注意事项? 卤肉过程中最忌讳的是什么? 归来归去来下句是什么 归来归去来的下一句是什么 普洱生茶对存放湿度有什么要求? 普洱茶存放条件 怎么防止蒜发芽 防止蒜发芽的方法 大学物理实验报告、思考题和考试题库总结! 不同温湿度环境下,普洱茶存储之间有什么样的差异? 杜绝茶叶发霉发酸!不同温、湿度环境下普洱茶存储的差异 普洱茶如何存放?记住这三点让你存出好普洱! 普洱茶怎么样存放最好 普洱茶保存的正确方法 CS 命令大全谁知道告诉我一下。踢人是什么命令?有没有复制名字的功能... 【高中英语系列】虚拟语气-在各种从句中的用法 尘归尘土归土的出自哪里是什么意思怎么理解尘归尘土归土的意思 吉拉啄木鸟外形特征 苹果4S 序列号DQJJM07GD7DF 是什么版本的 dnqhg2tgdtd3手机序列号4s 帮忙查下苹果序列号DX3KD10GDTD3是新机么?有没有可能是官方翻新版或者官... 新买的ipad2序列号:DLXGDFOLDKNV,求验证是否是翻新机,谢谢 syrup style女代言人在app的广告音乐一首韩文歌是什么 已知ax³+bx²+cx+d=(4x-1)³,试求: (提示:分别令x=1或x=... 我的三星笔记本Np450r4v-x0Bcn 有几个内存卡槽,要是加装要什么型号的内... 工伤期问工资待遇是怎么样的? 英语里有什么虚拟语气? 关于爱心的名人名言 爱心的名人名言 计算机领域有哪些值得推荐的网站? 怎样挽救胯大 英语中的所有虚拟语气? 怎么免费学电脑? 我老婆突然间用妇炎洁是怎么回事以前没用过 ...在一起半年多了,他听他伙计的说我不真心爱他,男朋友居