[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,是否能说明这种类型为引用类型?**