值类型与引用类型,值传递与引用传递

值传递和引用传递


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

一文整得明明白白~

Go全部都是值传递,不存在引用传递

值传递 是原始值copy出一份副本,然后传递; 引用传递 是直接传原始值的指针;

值传递并非不能修改原始值,当原始值是引用类型时(指针、map、slice、chan等这些),值传递就可以修改原始值 (值传递传的指针是原始值指针的副本,但两个指针都指向同一个地址)




值类型和引用类型


slice,map,channel,interface,func这5种数据类型 是引用类型,都(或者至少某个字段)是指针 (引用类型可以看作是对指针的封装)

(使用make函数创建的map,channel 其实都是一个指针,slice是其结构体SliceHeader的Data字段[2]是指针)

// SliceHeader is the runtime representation of a slice.
// It cannot be used safely or portably and its representation may
// change in a later release.
// Moreover, the Data field is not sufficient to guarantee the data
// it references will not be garbage collected, so programs must keep
// a separate, correctly typed pointer to the underlying data.
type SliceHeader struct {
 Data uintptr
 Len  int
 Cap  int
}

int、float、bool、array、sturct 是值类型


string比较有争议,感觉是值类型,但有种说法[3]也是引用类型


几种说法


说法1: “引用类型保存在堆上,值类型保存在栈上”?

这种说法是不准确的[4]

首先不要纠结字面意思,Java中(byte、short、int、long、float、double)、字符型(char)、布尔型(boolean)这些基本类型数据直接保存在栈中,而类、接口、数组数据是保存在堆中,栈只是保存一个指向堆内存的指针。

一文理清 Go 引用的常见疑惑[5]




浅拷贝与深拷贝


讨论值传递和引用传递时,其实就是看值类型变量和引用类型变量作为函数参数时,修改形参是否会影响到实参

在Go语言中除了五个引用类型,其他都是值类型:

  • slice

  • map

  • channel

  • interface

  • func()


引用类型作为参数时,称为浅拷贝,形参改变,实参数跟随变化.因为传递的是地址,形参和实参都指向同一块地址

值类型作为参数时,称为深拷贝,形参改变,实参不变,因为传递的是值的副本,形参会新开辟一块空间,与实参指向不同

如果希望值类型数据在修改形参时实参跟随变化,可以把参数设置为指针类型


Golang基础(闭包、值传递与引用传递)[6]


需要注意的是,在 Go 语言中,闭包内部引用外部变量时,实际上是引用了外部变量的地址。因此,闭包的行为类似于引用传递,而不是像一般的函数参数那样的值传递。

一般认为这种类型才是真正意义上的闭包(即不传参数进去)

package main

func main() {
 i := 1
 func() {
  i = 2
  print(i)
 }()

 print(i)
}

实际上,我把这种情况也认为是闭包:

package main

func main() {
 i := 1
 func(i int) {
  i = 2
  print(i)
 }(i)

 print(i)
}

即传参进去,那里面的改动就不会影响外面,外面的改动也不会影响里面(在传进去那一刻就定住了~)


当然如果这样,里面的改动还是会改变外面的值

package main

func main() {
 i := 1
 func(k int) {
  i = 2
  print(i)
 }(i)

 print(i)
}

参考资料

[1]

Go语言参数传递是传值还是传引用: https://www.flysnow.org/2018/02/24/golang-function-parameters-passed-by-value.html

[2]

SliceHeader的Data字段: https://gitee.com/cuishuang/go1.16/blob/master/src/reflect/value.go#L2335

[3]

有种说法: https://www.cnblogs.com/xbblogs/p/11102970.html

[4]

不准确的: https://blog.csdn.net/nicepainkiller/article/details/78213694

[5]

一文理清 Go 引用的常见疑惑: https://zhuanlan.zhihu.com/p/84580859

[6]

Golang基础(闭包、值传递与引用传递): https://blog.csdn.net/qq_31387691/article/details/109180143

本文由 mdnice 多平台发布

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值