Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >[Introduction]Go特殊的引用类型:值传递/指针传递/引用传递

[Introduction]Go特殊的引用类型:值传递/指针传递/引用传递

原创
作者头像
Wzy_CC
修改于 2020-08-10 06:36:44
修改于 2020-08-10 06:36:44
1.6K0
举报

结论:golang中函数传参只有值传递

变量名/变量值/变量地址

代码语言:txt
AI代码解释
复制
var a = 10
log.Printf("%p\n",a) // 变量地址假设为 0x00000001

变量名a,变量值10,变量地址0x00000001

指针/引用

指针变量存放其他变量的地址。在C++中引用就是变量的另一名字

变量名本身并没有作用,只相当于代号利于程序员编程,引用作为别名本质上还是指向同一个内存地址。指针本质上占用一小段内存空间

值传递

值传递就是深拷贝,在函数内传递的副本,并不会影响函数外的实参

在函数调用时,将实参深拷贝后压栈

指针传递

形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作

引用传递 for C++

在C++中的引用传递本质上将实参的地址传递到函数中,和指针传递效果类似

在Go中的函数调用只有值传递,但是存在引用类型slice、map、channel

代码语言:txt
AI代码解释
复制
array := []int{1,2,3}
arrayslice := array[:]

GO中“特殊的引用类型”

能够通过make()创建的都是引用类型,比图slicemapslice本质上是一个指向数组内存空间的一个指针类型:

代码语言:txt
AI代码解释
复制
type Slice struct {
    point Point // 内存地址
    len int
    cap int
}

所以本质上对slice切片的赋值,实质上就是对Slice这个结构体进行深拷贝,对于Point来说自然是指向同一段空间了。虽然是值传递,但是本质上是两个Slice对象,传递的对象是指针,指针相同,因此算是特殊的值传递。map同理

在Golang中的例子可以比较直观反应切片特性:

代码语言:txt
AI代码解释
复制
func printAddr(s []int) { // 打印数组地址 值参数
    log.Printf("printAddr:%p\n", &s[0])
}

func printAddrPoint(ps \*[]int) { // 打印数组地址 指针参数
    log.Printf("printAddrPoint:%p\n", &((\*ps)[0]))
}

func main() {
    array := [3]int{1, 2, 3}   // 数组   commit 1
    // array := []int{1, 2, 3} // 切片   commit 2
    log.Printf("array:%p\n", &array)
    arrayslice := array[:] // 切片
    log.Printf("arrayslice:%p\n", &arrayslice)
    printAddr(arrayslice)
    printAddrPoint(&arrayslice)
}

控制台输出:

代码语言:txt
AI代码解释
复制
2020/08/07 15:15:35 array:0xc00000e3c0
2020/08/07 15:15:35 arrayslice:0xc000004620
2020/08/07 15:15:35 printAddr:0xc00000e3c0
2020/08/07 15:15:35 printAddrPoint:0xc00000e3c0

本质上是因为切片传递依旧是值传递,虽然结构体本身不是一个地址,但是里面包含的起始地址都是array[0]这也可以解释为什么三者相同

注释掉commit1,解注释掉commit2,再次运行结果如下:

代码语言:txt
AI代码解释
复制
2020/08/07 15:22:42 array:0xc0000044a0
2020/08/07 15:22:42 arrayslice:0xc000004640
2020/08/07 15:22:42 printAddr:0xc00000e3c0
2020/08/07 15:22:42 printAddrPoint:0xc00000e3c0

猜测array[0]的地址不出意外也应该是0xc00000e3c0,验证:

代码语言:txt
AI代码解释
复制
func main() {
    array := []int{1, 2, 3} // 数组
    log.Printf("array[0]:%p\n", &array[0])
}

控制台输出:

代码语言:txt
AI代码解释
复制
2020/08/07 15:37:19 array[0]:0xc00000e3c0

arrayarray[0]的地址不一致。array[0]和其他切片的第零个元素的地址一样,继续尝试后可以得出结论:

**1.数组地址等同于数组首元素地址,和C是一致的**

**2.切片(结构体)的地址和切片首元素的地址是不一致的**,猜测声明切片的时候顺序是先创建了数组,然后初始化切片结构体为数组引用?

参考链接

Go语言参数传递是传值还是传引用

我对变量产生了这些想法

Golang中函数传参存在引用传递吗?

理解 Golang 中 slice 的底层设计

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Go语言 参数传递究竟是值传递还是引用传递
之前我们谈过,在Go语言中的引用类型有:映射(map),数组切片(slice),通道(channel),方法与函数。起初我一直认为,除了以上说的五种是引用传递外,其他的都是值传递,也就是Go语言中存在值传递与引用传递,但事实真的如所想的这样吗?
兔云小新LM
2022/11/21
1.6K0
Go语言 参数传递究竟是值传递还是引用传递
Go 中slice, map, chan, strcuct 是值传递么?
发现没有,切片的地址和形参的地址为啥一样, 难道也问题?不是值传递?上面可以看到,我们并没有用取址符 & 来进行地址转换,就把 slice 打印出来来,再测试一下:
王小明_HIT
2021/04/30
1.3K0
Golang中函数传参存在引用传递吗?
官方文档已经明确说明:Go里边函数传参只有值传递一种方式,为了加强自己的理解,再来把每种传参方式进行一次梳理。
大愚
2018/09/13
2.3K0
Golang中函数传参存在引用传递吗?
一文理清 Go 引用的常见疑惑
之所以要谈它,一方面是之前的我也有些概念混乱,想梳理下,另一方面是因为很多人对引用都有疑问。我经常会看到与引用有关的问题。
波罗学
2019/09/29
5340
一文理清 Go 引用的常见疑惑
用汇编带你看Golang里到底有没有值类型、引用类型
不管使用什么语言,日常生活中能常在技术群中看到类似这样的问题(当然这个图是我瞎编的,真实的讨论会比图中 peace 一些~):
薯条的编程修养
2022/08/10
8340
用汇编带你看Golang里到底有没有值类型、引用类型
Java 02 - 值传递与引用传递
首先我们要知道, 值传递和引用传递是一种求值策略(Evaluation Stragtegy), 表示的是调用函数的时候, 对于参数传递方式的描述, 而不是对参数本身类型的描述. 值类型和引用类型是两种内存分配方式, 值类型是在调用栈上分配, 而引用类型是在堆上分配. 一个是描述的内存分配方式, 一个是描述参数求值策略, 二者并无依赖和约束关系.
Reck Zhang
2021/08/11
8200
指针值传递、地址传递和引用传递
执行结果中并未输出字符串hello其实这里主函数调用fun函数,形参向实参传递参数的时候,发生的是拷贝。在fun函数中对局部指针变量p的任何修改都不会影响到主函数中的指针变量p。 下面简单的用函数栈帧空间图分析一下:
lexingsen
2022/02/24
1.8K0
指针值传递、地址传递和引用传递
浅析按值传递与按引用传递
下列关于按值传递与按引用传递的描述中,正确的是( )。A.按值传递不会改变实际参数的数值 B.按引用传递能改变实际参数的参考地址C.按引用传递能改变实际参数的内容 D.按引用传递不能改变实际参数的参考地址
田维常
2019/12/17
1.3K0
清源正本,鉴往知来,Go lang1.18入门精炼教程,由白丁入鸿儒,Golang中引用类型是否进行引用传递EP18
    开篇明义,Go lang中从来就不存在所谓的“引用传递”,从来就只有一种变量传递方式,那就是值传递。因为引用传递的前提是存在“引用变量”,但是Go lang中从来就没有出现过所谓的“引用变量”,所以也就不可能存在引用传递这种变量传递的方式。
用户9127725
2022/09/26
3260
Golang函数参数的值传递和引用传递
值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数
仙人技术
2021/08/31
2.7K0
Golang函数参数的值传递和引用传递
java是值传递还是引用传递 知乎_按值调用和按引用调用
最近整理面试题,整理到值传递、引用传递,到网上搜了一圈,争议很大。带着一脸蒙圈,线上线下查了好多资料。最终有所收获,所以分享给大家,希望能对你有所帮助。 首先说下我的感受,这个题目出的很好,但是在 Java 中这个题目是有问题的(在下面我会解释)。并且,有很多结论是 Java 中只有 值传递。我认为这样说不够严谨。当然如果针对 Java 语言本身来讲,Java 中只有 值传递,没有引用传递,是正确的。但是如果针对 值传递,引用传递的定义来说,Java 中还是有引用传递的。下面来分析:
全栈程序员站长
2022/11/03
1K0
go的值传递和引用传递以及引用类型的问题
package main import( "fmt" ) // int string 参数传递是值传递 非引用类型 // map 参数传递是值传递 引用类型 var a int = 9 var b string = "aa" var c map[int]int func modify1(a int) { fmt.Println("值:",a) fmt.Println("地址:",&a) a = 10 fmt.Println("值:", a) fmt.Println("地址:", &a) } func modify2(a string) { fmt.Println("值:",a) fmt.Println("地址:",&a) a = "cccc" fmt.Println("值:", a) fmt.Println("地址:", &a) } func modify3(a map[int]int) { fmt.Println("值:",a) fmt.Printf("地址:%p\n",&a) a[4] = 10 fmt.Println("值:", a) fmt.Printf("地址:%p\n",&a) } func main(){ fmt.Println("值:", a) fmt.Println("地址:", &a) modify1(a) fmt.Println("值:", a) fmt.Println("地址:", &a) fmt.Println("值:", b) fmt.Println("地址:", &b) modify2(b) fmt.Println("值:", b) fmt.Println("地址:", &b) c = make(map[int]int) c[4] = 9 fmt.Println("值:", c) fmt.Printf("地址:%p\n", &c) modify3(c) fmt.Println("值:", c) fmt.Printf("地址:%p\n", &c) } //Go语言中所有的传参都是值传递(传值),都是一个副本,一个拷贝。因为拷贝的内容有时候是非引用类型(int、string、struct等这些),这样就在函数中就无法修改原内容数据;有的是引用类型(指针、map、slice、chan等这些),这样就可以修改原内容数据。是否可以修改原内容数据,和传值、传引用没有必然的关系。在C++中,传引用肯定是可以修改原内容数据的,在Go语言里,虽然只有传值,但是我们也可以修改原内容数据,因为参数是引用类型。这里也要记住,引用类型和传引用是两个概念。再记住,Go里只有传值(值传递)。
公众号-利志分享
2022/04/25
8250
15.Go复合类型-指针
前面我们讲过存储数据的方式,可以通过变量,或者复合类型中的数组,切片,Map,结构体。
Devops海洋的渔夫
2022/01/17
2490
15.Go复合类型-指针
细说值传递、引用传递和地址传递
形式参数:是在定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传入的参数。
闫同学
2023/10/14
3260
java——值传递和引用传递
我们可以看到valueCross方法执行后,实参age和weight的值并没有发生变化,这是什么原因?
说故事的五公子
2019/09/11
1.3K0
java——值传递和引用传递
Java到底是引用传递还是值传递?
首先回顾一下在程序设计语言中有关将参数传递给方法(或函数)的一些专业术语。 按值调用(call by value)表示方法接收的是调用者提供的值,而按引用调用(call by reference)表示方法接收的是调用者提供的变量地址。一个方法可以修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量值。它用来描述各种程序设计语言(不只是 Java)中方法参数传递方式。
黑洞代码
2021/01/14
8260
Java到底是引用传递还是值传递?
你们不要再吵了! Java只有值传递..
对于引用类型 str,赋值运算符只会改变引用中所保存的地址,虽然原来的地址被覆盖掉了,str指向了一个新的对象,但是原来的那个老对象没有发生变化,他还是老老实实待在原来的地方!!!
玖柒的小窝
2021/11/05
4100
你们不要再吵了! Java只有值传递..
Go语言参数传递是传值还是传引用
其实对于传值和传引用,是一个比较古老的话题,做研发的都有这个概念,但是可能不是非常清楚。对于我们做Go语言开发的来说,也想知道到底是什么传递。
飞雪无情
2018/08/28
2.4K0
Go语言参数传递是传值还是传引用
Java 引用传递和值传递
这个问题的关键在于 a,b,x,y 的地址指向; y = x 与 b = a 是不等价的!! 发生改变的是 y 指向的值变成了和 x 指向的相同, 此时 y = AB(因为append方法改变的x原有的值) 而此时 b 的指向并没有发生改变。
星尘的一个朋友
2020/11/25
1.3K0
Java中的值传递与引用传递详解
方法调用是编程语言中非常重要的一个特性,在方法调用时,通常需要传递一些参数来完成特定的功能。Java语言提供了两种参数传递的方式:值传递和引用传递。
良月柒
2019/03/20
2.3K0
Java中的值传递与引用传递详解
推荐阅读
相关推荐
Go语言 参数传递究竟是值传递还是引用传递
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档