[Introduction]Go特殊的引用类型:值传递/指针传递/引用传递
结论:golang中函数传参只有值传递
变量名/变量值/变量地址
var a = 10
log.Printf("%pn",a) // 变量地址假设为 0x00000001
变量名a,变量值10,变量地址0x00000001
指针/引用
指针变量存放其他变量的地址。在C++中引用就是变量的另一名字
变量名本身并没有作用,只相当于代号利于程序员编程,引用作为别名本质上还是指向同一个内存地址。指针本质上占用一小段内存空间
值传递
值传递就是深拷贝,在函数内传递的副本,并不会影响函数外的实参
在函数调用时,将实参深拷贝后压栈
指针传递
形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作
引用传递 for C++
在C++中的引用传递本质上将实参的地址传递到函数中,和指针传递效果类似
在Go中的函数调用只有值传递,但是存在引用类型slice、map、channel
array := []int{1,2,3}
arrayslice := array[:]
GO中“特殊的引用类型”
能够通过make()
创建的都是引用类型,比图slice
和map
,slice
本质上是一个指向数组内存空间的一个指针类型:
type Slice struct {
point Point // 内存地址
len int
cap int
}
所以本质上对slice
切片的赋值,实质上就是对Slice
这个结构体进行深拷贝,对于Point
来说自然是指向同一段空间了。虽然是值传递,但是本质上是两个Slice
对象,传递的对象是指针,指针相同,因此算是特殊的值传递。map
同理
在Golang中的例子可以比较直观反应切片特性:
func printAddr(s []int) { // 打印数组地址 值参数
log.Printf("printAddr:%pn", &s[0])
}
func printAddrPoint(ps *[]int) { // 打印数组地址 指针参数
log.Printf("printAddrPoint:%pn", &((*ps)[0]))
}
func main() {
array := [3]int{1, 2, 3} // 数组 commit 1
// array := []int{1, 2, 3} // 切片 commit 2
log.Printf("array:%pn", &array)
arrayslice := array[:] // 切片
log.Printf("arrayslice:%pn", &arrayslice)
printAddr(arrayslice)
printAddrPoint(&arrayslice)
}
控制台输出:
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,再次运行结果如下:
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
,验证:
func main() {
array := []int{1, 2, 3} // 数组
log.Printf("array[0]:%pn", &array[0])
}
控制台输出:
2020/08/07 15:37:19 array[0]:0xc00000e3c0
array
和array[0]
的地址不一致。array[0]
和其他切片的第零个元素的地址一样,继续尝试后可以得出结论:
**1.数组地址等同于数组首元素地址,和C是一致的**
**2.切片(结构体)的地址和切片首元素的地址是不一致的**,猜测声明切片的时候顺序是先创建了数组,然后初始化切片结构体为数组引用?
参考链接
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法