go的值传递和引用传递;go函数传递切片示例

go中预定义引用类型:slice、map、channel

函数传递map

func main() {
	m := make(map[string]int)
	m["aaa"]=100
	m["bbb"]=200
	fmt.Printf("pointer: %p, target: %v\n",&m,m)
	testTransfer3(m)
	fmt.Printf("pointer: %p, target: %v\n",&m,m)
}

func testTransfer3(m map[string]int){
	fmt.Printf("pointer: %p, target: %v\n",&m,m)
	m["aaa"]=1
}

输出:
pointer: 0xc00008a018, target: map[aaa:100 bbb:200]
pointer: 0xc00008a028, target: map[aaa:100 bbb:200]
pointer: 0xc00008a018, target: map[aaa:1 bbb:200]


引用类型,传参时是【指针拷贝传递】,拷贝的是【指针】。即方法内的变量与方法外的变量地址不同(拷贝时新创建变量),但是指向相同(拷贝出来的指针与原指针指向相同)。

 

函数传递slice

例一
func main() {
	var slice1=[]int {1,2,3}
	fmt.Printf("pointer: %p, target: %v\n",&slice1,slice1)
	testTransfer3(slice1)
	fmt.Printf("pointer: %p, target: %v\n",&slice1,slice1)
}
func testTransfer3(slice []int){
	fmt.Printf("pointer: %p, target: %v\n",&slice,slice)
	slice[0] = 0
}
输出:
pointer: 0xc0000044c0, target: [1 2 3]
pointer: 0xc000004520, target: [1 2 3]
pointer: 0xc0000044c0, target: [0 2 3]

引用类型,传参时是【指针拷贝传递】,拷贝的是【指针】。即方法内的变量与方法外的变量地址不同(拷贝时新创建变量),但是指向相同(拷贝出来的指针与原指针指向相同)。改变的是指针指向的切片内容,所以所有指向该切片的指针都受影响。


例二
func main() {
	var slice1=[]int {1,2,3}
	fmt.Printf("pointer: %p, target: %v\n",&slice1,slice1)
	testTransfer3(slice1)
	fmt.Printf("pointer: %p, target: %v\n",&slice1,slice1)
}
func testTransfer3(slice []int){
	fmt.Printf("pointer: %p, target: %v\n",&slice,slice)
	slice = append(slice, 4,5)
}
输出:
pointer: 0xc0000044c0, target: [1 2 3]
pointer: 0xc000004520, target: [1 2 3]
pointer: 0xc0000044c0, target: [1 2 3]

引用类型,传参时是【指针拷贝传递】,拷贝的是【指针】。即方法内的变量与方法外的变量地址不同(拷贝时新创建变量),但是指向相同(拷贝出来的指针与原指针指向相同)。方法内改变了slice1的指向,方法外的slice1指向未改变。


例三
func main() {
	var slice1 = make([]int,3,10)
	slice1[0] = 1
	slice1[1] = 2
	slice1[2] = 3
	fmt.Printf("pointer: %p, target: %v,%v,%v\n",&slice1,slice1,len(slice1),cap(slice1))
	testTransfer3(slice1)
	fmt.Printf("pointer: %p, target: %v,%v,%v\n",&slice1,slice1,len(slice1),cap(slice1))
}
func testTransfer3(slice []int){
	fmt.Printf("pointer: %p, target: %v,%v,%v\n",&slice,slice,len(slice),cap(slice))
	slice = append(slice, 4,5)
}
输出:
pointer: 0xc0000044c0, target: [1 2 3],3,10
pointer: 0xc000004520, target: [1 2 3],3,10
pointer: 0xc0000044c0, target: [1 2 3],3,10

引用类型,传参时是【指针拷贝传递】,拷贝的是【指针】。即方法内的变量与方法外的变量地址不同(拷贝时新创建变量),但是指向相同(拷贝出来的指针与原指针指向相同)。方法内改变了slice1的指向,方法外的slice1指向未改变。


例四
func main() {
	var slice1=[]int {1,2,3}
	fmt.Printf("pointer: %p, target: %v\n",&slice1,slice1)
	testTransfer3(&slice1)
	fmt.Printf("pointer: %p, target: %v\n",&slice1,slice1)
}
func testTransfer3(slice *[]int){
	fmt.Printf("pointer: %p, target: %v\n",slice,*slice)
	*slice = append(*slice, 4,5)
}
输出:
pointer: 0xc0000044c0, target: [1 2 3]
pointer: 0xc0000044c0, target: [1 2 3]
pointer: 0xc0000044c0, target: [1 2 3 4 5]

值类型,传参时是【值拷贝传递】,拷贝的是【值(slice1的地址)】。方法内改变了指针指向的内容,方法外的slice1与方法内为同一指针,内容也改变。

不管是指针、引用类型,还是其他类型参数,都是值拷贝传递,区别无非是拷贝目标对象,还是拷贝指针而已。在函数调用前,会为形参和返回值分配内存空间,并将实参拷贝到形参内存。


版权声明:本文为libie_lt原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。