值类型与引用类型 · golang · 看云
[TOC]
### **对比**
Go语言的数据类型有 值类型 与 引用类型 两种。
* 值类型:在初始化、赋值时,两个变量互不影响;参数传递时,传递的是一个副本
* 引用类型:在初始化、赋值时,两个变量实际是同一个;参数传递时,传递的是变量本身。
在Go语言中,只有slice、map、interface、channel是引用类型,其他的都是值类型。
### **示例**
##### **值类型**
举个例子,数组array类型是值类型,那么在使用相同的类型的变量初始化另一个变量时,两个变量互不影响,如下array1与array2是两个不同的数组:
```
array1 := [10]int64{}
array2 := array1
```
在赋值时,只是把array1的内容拷贝到array2中,array1的修改不会再影响array2
```
array1 := [10]int64{1,2}
var array2 [10]int64{}
array2 = array1
array1[0] = 100 // array2[0] 不会变
```
##### **引用类型**
切片是引用类型,所以当使用一个切片初始化另一个切片时,两个切片实际是同一个
```
slice1 := make([]int64, 1, 10) // 初始化一个len为1,cap为10的切片
slice2 := slice1
slice1[0] = 1 // slice2[0] 也会变成1
```
### **直观判断**
上面我们已经列举了所有的引用类型,但是我们如何直观地判断一个数据类型是值类型还是引用类型呢?
其实,我们可以通过声明语义和赋值来判断。
比如,数组的底层其实有一个固定指针ptr和长度len两个变量。数组在声明的时候(`var array1 [10]int64`),必须指定长度,然后系统会在栈空间内分配一个内存空间;也就是说,声明语义完成后,ptr和len的值已经固定了。当我们声明另一个数组时(`var array2 [10]int64`),array2的地址空间和array1是不一样的,而且两个数组的底层ptr又是不能变的,所以赋值的时候,就不能把array2.ptr赋值为array1.ptr,而只能把array2的10个数据拷贝到array1的地址空间中。这样子一推断,数组只能是值类型。
**Q:如果某种类型的变量只声明,声明后该变量的值为nil,是否能说明这种类型为引用类型?**