Go语言中函数参数传递采用的是值传递的方式。所谓“值传递”,就是将实际参数在内存 中的表示逐位拷贝到形式参数中。对于像整型、数组、结构体这类类 型,它们的内存表示就是它们自身的数据内容,因此当这些类型作为实参类型时,值传递 拷贝的就是它们自身,传递的开销也与它们自身的大小成正比。

但是像 string、切片、map 这些类型就不是了,它们的内存表示对应的是它们数据内容 的“描述符”。当这些类型作为实参类型时,值传递拷贝的也是它们数据内容的“描述 符”,不包括数据内容本身,所以这些类型传递的开销是固定的,与数据内容大小无关。 这种只拷贝“描述符”,不拷贝实际数据内容的拷贝过程,也被称为“浅拷贝”。

函数声明

  1. func 函数名(参数) (返回值){
  2. 函数体
  3. }

函数声明示例

  1. // 当形参参数类型相同时,可以只保留最后一个元素类型,前面的类型都可以省略
  2. func add(n1, n2 int) int {
  3. return n1 + n2
  4. }
  5. func main() {
  6. fmt.Println(add(1, 1)) // 2
  7. }

函数的变长参数

  1. func add(n1, n2 int, args ...int) int {
  2. for _, v := range args {
  3. fmt.Println(v)
  4. }
  5. return n1 + n2
  6. }
  7. func main() {
  8. n := []int{6, 7, 8}
  9. fmt.Println(add(1, 1, n...)) // 6 7 8 2
  10. }

函数的多返回值

  1. func add(n1, n2 int) (int, int) {
  2. r1 := n1 + n2
  3. r2 := n1 * n2
  4. return r1, r2
  5. }
  6. func main() {
  7. fmt.Println(add(1, 1)) // 2 1
  8. }

匿名函数

匿名函数就是没有函数名的函数,当我们不希望给函数起名字的时候,可以使用匿名函数,匿名函数不能够独立存在,它可以被赋值于某个变量或直接对匿名函数进行调用。

  1. // 将匿名函数保存到变量
  2. a := func() {
  3. fmt.Println("test1")
  4. }
  5. a() // 调用
  6. // 直接对匿名函数进行调用,最后的一对括号表示对该匿名函数的直接调用执行
  7. func() {
  8. fmt.Println("test2")
  9. }() // 调用

延迟函数

defer关键字 + 函数调用来实现延迟函数
延迟函数在函数return之后退出之前执行,仅在函数退出之前执行,for循环内或其它啥的用这个不起作用

  1. func test(n1, n2 int) string {
  2. // 延迟执行:return调用以后,在函数退出之前执行。注意:仅仅在函数退出之前执行,for循环内或其他啥的用这个是不起作用的
  3. // 延迟函数多用于打开文件、延迟关闭、处理(处理出现错误)
  4. defer func() {
  5. fmt.Println("defer")
  6. }()
  7. fmt.Println("befor")
  8. fmt.Println(n1 / n2)
  9. fmt.Println("end")
  10. return ""
  11. }
  12. func main() {
  13. test(1, 1) // befor 1 end defer
  14. test(1, 0) // 手动来一个除零异常, 那么得到的结果为: befor defer 然后是异常信息
  15. }