zl程序教程

您现在的位置是:首页 >  后端

当前栏目

Go 函数 参数值传递

Go 函数 传递 参数值
2023-09-14 09:15:18 时间

函数


函数为什么是一等公民呢?和其他主流语言不同,在go里面函数的地位是不一样的。

与其他主要编程语⾔的差异

  1. 可以有多个返回值
  2. 所有参数都是值传递:slice,map,channel 会有传引⽤的错觉(在传递过去的时候,传入到函数当中,在函数里面修改参数的值,外面也可以感受到,难道这不是传引用吗?😳😳😳😳😳😳😳😳😳其实这是一个错觉,就比如slice,切片背后实际上对应的是数组,切片本身是一个数据结构,数据结构里面包含指向数组到指针,即便是在传值的情况下,结构被复制到函数里面了,通过指向数组到指针去操作具体值到时候,其实操作的是同一块空间,所以就会有一种传引用到错觉,实际上是结构被复制了,包含的指针指向到是同一个后端到数组,所以才有这个错觉。)
  3. 函数可以作为变量的值
  4. 函数可以作为参数和返回值

 

 

传递参数类型 值类型 引用类型


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]
}

看下图理解最方便:😂😂😂😂😂