一、前言
我在刚开始学习golang的时候,被值传递和引用传递困扰了一段时间,因为我之前是学习Java的,深受Java面向对象思想的影响,转成golang的时候就会想不通结构体等类型(看起来像是Java中自己定义的类),为什么会是值传递,所以总结一篇文章来通过例子简单分析一下这个问题。
二、例子
先说结论:golang中都是采用值传递,即拷贝传递,也就是深拷贝。没有引用传递。之所有有些看起来像是引用传递的场景,是因为Golang中存在着引用类型,如slice、map、channel、function、pointer这些天生就是指针的类型,在传递的时候是复制的地址。引用类型作为参数时,称为浅拷贝,形参改变,实参数跟随变化。因为传递的是地址,形参和实参都指向同一块地址。(切片是引用类型,数组是值类型)切片和数组的区别
package main
import(
"fmt"
)
func main(){
//map
m := make(map[int]string)
m[0] = "a"
m[1] = "b"
changeMap(m)
fmt.Printf("map:%+v", m) //输出 map:map[0:aaa 1:b]
fmt.Println()
//array
var a = [2]string{"a", "b"}
changeArray(a)
fmt.Printf("array:%+v", a) //输出array:[a b]
fmt.Println()
//slice
var s = []string{"a", "b"}
changeSlice(s)
fmt.Printf("slice:%+v", s) //输出slice:[aaa b]
}
func changeMap(m map[int]string) {
m[0] = "aaa"
}
func changeArray(a [2]string) {
a[0] = "aaa"
}
func changeSlice(s []string) {
s[0] = "aaa"
}
三、分析
通过上面的例子可以看出来map和slice都是引用类型,即函数内部是可以改变参数的值的。而array是值类型,不管函数内部如何改变参数,都是改变的拷贝值,并未对原值进行处理。
所以,golang中除了特定的几个指针类型之外,其他的所有类型,包括自己创建的结构体都是深层复制,即值类型。像是结构体,不像Java中只是把指针赋值给接收的变量,而是新开辟了一块内存空间,把所有的属性复制过去了,创建了一个一模一样的结构体。