Go 函数 参数值传递
原创
©著作权归作者所有:来自51CTO博客作者wx5bcd2f496a1cf的原创作品,请联系作者获取转载授权,否则将追究法律责任
函数
函数为什么是一等公民呢?和其他主流语言不同,在go里面函数的地位是不一样的。
与其他主要编程语⾔的差异
- 可以有多个返回值
- 所有参数都是值传递:slice,map,channel 会有传引⽤的错觉(在传递过去的时候,传入到函数当中,在函数里面修改参数的值,外面也可以感受到,难道这不是传引用吗?😳😳😳😳😳😳😳😳😳其实这是一个错觉,就比如slice,切片背后实际上对应的是数组,切片本身是一个数据结构,数据结构里面包含指向数组到指针,即便是在传值的情况下,结构被复制到函数里面了,通过指向数组到指针去操作具体值到时候,其实操作的是同一块空间,所以就会有一种传引用到错觉,实际上是结构被复制了,包含的指针指向到是同一个后端到数组,所以才有这个错觉。)
- 函数可以作为变量的值
- 函数可以作为参数和返回值
传递参数类型 值类型 引用类型
1) 值传递 值类型--》值拷贝
在 Go 语言中参数传递默认均为值传递(形参为实参变量的副本),
对于引用类型数据因其底
层共享数据结构,所以在函数内可对引用类型数据修改从而影响函数外的原变量信息
2) 引用传递。引用类型的时候--》也是值拷贝,只不过底层有个地址,导致使用的地址空间是一样的,所以在函数内部是可以影响函数外面变量的
所以go语言当中都是值拷贝,也就是值传递,不能说在函数里面是引用传递,其次在值传递的时候
为什么引用类型的参数可以影响函数外表的变量?因为值拷贝的时候底层是有地址和指针的。
可以通过将变量的地址通过指针类型递给函数,此时可通过指针对函数外的原变量进行修改。
先来看看变量的作用域
func main() {
name := "jack"
nums := []int{}
fmt.Println(name,nums)
func(){
fmt.Println(name,nums)
name = "lucas"
nums = []int{1,2,3}
fmt.Println(name,nums)
}()
fmt.Println(name,nums)
}
jack []
jack []
lucas [1 2 3]
lucas [1 2 3]
func main() {
name := "jack"
nums := []int{}
fmt.Println(name,nums)
func(){
fmt.Println(name,nums)
name := "lucas"
nums := []int{1,2,3}
fmt.Println(name,nums)
}()
fmt.Println(name,nums)
}
jack []
jack []
lucas [1 2 3]
jack []
值类型的参数和引用类型的参数
func main() {
name := "jack"
nums := []int{1,2,3}
fmt.Println(name,nums)
func(pname string,pnums []int){
fmt.Println(pname,pnums) //jack [1 2 3]
pname = "lucas"
pnums = append(pnums,4,5,6) //大于cap了,所以产生了新切片,和原来的没关系了
fmt.Println(pname,pnums) //lucas [1 2 3 4 5 6]
}(name,nums)
fmt.Println(name,nums) //jack [1 2 3]
}
可以看到在append之后会产生新的切片! 😏😏😏😏
a := []int{1,2,3}
fmt.Printf("%p,%d,%d\n",&a,len(a),cap(a))
b := append(a,4,5,6)
fmt.Printf("%p,%d,%d",&b,len(b),cap(b))
0xc0000a6018,3,3
0xc0000a6030,6,6
上面是pnums = 重新赋值,指向另外一个地方了,所以对原来的切片没有影响,如果是pnums[0] = 100就是对原来的切片进行修改,因为底层有指针,指向的数组是同一个。
func main() {
name := "jack"
nums := []int{1,2,3}
fmt.Println(name,nums)
func(pname string,pnums []int){
fmt.Println(pname,pnums) //jack [1 2 3]
pname = "lucas"
pnums[0] = 100
fmt.Println(pname,pnums) //lucas [100 2 3]
}(name,nums)
fmt.Println(name,nums) //jack [100 2 3]
}
看下图理解最方便:😂😂😂😂😂