一、前言
我在刚开始学习golang的时候,被值传递和引用传递困扰了一段时间,因为我之前是学习Java的,深受Java面向对象思想的影响,转成golang的时候就会想不通结构体等类型(看起来像是Java中自己定义的类),为什么会是值传递,所以总结一篇文章来通过例子简单分析一下这个问题。
二、例子
先说结论: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中只是把指针赋值给接收的变量,而是新开辟了一块内存空间,把所有的属性复制过去了,创建了一个一模一样的结构体。