6.1 介绍

Go的函数也可以作为一个参数,只要函数的返回值能对应上即可。
Go不支持函数重载,函数重载就是同名函数,有不同的形参不同的返回值。
现在Go支持泛型了,也就是支持多种类型的函数。
Go的函数可以返回多个值。

6.2 参数传递

传递给函数的参数,有两种:

  1. - **值转递**,就是把变量的值复制一份副本传递给函数,函数内是对该副本进行操作。
  2. - **引用传递**,就是把变量的指针复制一份副本传递给函数,函数内对该副本进行操作会影响到变量本身的值。

所以我们可以认为,引用传递其实也是值传递。
传递指针比传递值副本的消耗要低很多。
slice,map,interface,channel都是引用传递。

6.3 空白符

下划线_是Go中函数的空白符,用于接收函数的返回值,但是这个返回值后面用不到,但是Go中不用的量会编译出错。所以用空白符来接收。
实际上,空白符是一个只写不可读变量。空白符接收返回值,然后丢弃。

6.4 变长参数

变长参数就是一个函数的形参,可以接收任意个,不是固定指定数量。

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. test(5, 6, 7, 8, 9, 10)
  7. }
  8. func test(s ...int) { //不指定参数数量
  9. if len(s) == 0 {
  10. fmt.Println("一个参数都没传进来")
  11. } else {
  12. for i, k := range s {
  13. fmt.Print(i)
  14. fmt.Println(k)
  15. }
  16. }
  17. }

6.5 defer语句

defer语句是在函数返回之前最后执行的语句,一般是用来释放一些资源,以免忘记。
defer的位置可以任意放,但是defer语句的执行顺序是逆序的。

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. fmt.Println("1")
  7. defer fmt.Println("2")
  8. fmt.Println("3")
  9. }
  10. //1 3 2

6.6 内置函数

内置函数不要导入包,就能直接使用。

名称 说明
close() 用于管道通信
len()、cap() len() 用于返回某个类型的长度或数量(字符串、数组、切片、map 和管道);cap() 是容量的意思,用于返回某个类型的最大容量(只能用于数组、切片和管道,不能用于 map)
new()、make() new() 和 make() 均是用于分配内存:new() 用于值类型和用户定义的类型,如自定义结构,make 用于内置引用类型(切片、map 和管道)。它们的用法就像是函数,但是将类型作为参数:new(type)、make(type)。new(T) 分配类型 T 的零值并返回其地址,也就是指向类型 T 的指针。它也可以被用于基本类型:v := new(int)。make(T) 返回类型 T 的初始化之后的值,因此它比 new() 进行更多的工作。new() 是一个函数,不要忘记它的括号
copy()、append() 用于复制和连接切片
panic()、recover() 两者均用于错误处理机制
print()、println() 底层打印函数,在部署环境中建议使用 fmt 包
complex()、real ()、imag() 用于创建和操作复数

6.7 递归函数

在函数体内,又调用自身,成为函数递归,最典型的就是阶乘计算和斐波那契数列。

  1. package main
  2. import "fmt"
  3. func main() {
  4. result := 0
  5. for i := 0; i <= 10; i++ {
  6. result = fibonacci(i)
  7. fmt.Printf("fibonacci(%d) is: %d\n", i, result)
  8. }
  9. }
  10. func fibonacci(n int) (res int) {
  11. if n <= 1 {
  12. res = 1
  13. } else {
  14. res = fibonacci(n-1) + fibonacci(n-2)
  15. }
  16. return
  17. }

6.8 闭包

没有名称的函数成为匿名函数,如:func(a int, b int){}。
匿名函数不能像其他函数一样在main函数之外单独存在,有返回值的话,可以赋值给变量,然后通过变量来调用:

  1. package main
  2. import "fmt"
  3. func main() {
  4. result := func(a int, b int) int {
  5. return a + b
  6. }
  7. fmt.Println(result(5, 6))
  8. }

在函数内可以自调用,在函数后面传入参数:

  1. package main
  2. import "fmt"
  3. func main() {
  4. func(a int, b int) {
  5. sum := a + b
  6. fmt.Println(sum)
  7. }(5, 6)
  8. }

闭包 = 匿名函数 + 引用环境。
引用环境是什么意思呢?

  1. package main
  2. import "fmt"
  3. func Bibao() func(int) int { //返回一个func(int)int类型
  4. var n int = 10 //这个就是引用环境,它相当于C中的静态变量,会记忆上次的值
  5. return func(i int) int { //这里是匿名函数
  6. n = n + i
  7. return n
  8. }
  9. }
  10. func main() {
  11. f := Bibao() //声明一个闭包
  12. fmt.Println(f(1)) //10 + 1 = 11,参数是传到匿名函数中的
  13. fmt.Println(f(1)) //11 + 1 = 12
  14. }

多返回值也是可以的:

  1. package main
  2. import "fmt"
  3. func Bibao(ss string) func(int, string) (int, string) { //返回一个func(int)int类型
  4. var n int = 10 //这个就是引用环境,它相当于C中的静态变量,会记忆上次的值
  5. return func(i int, s string) (int, string) { //这里是匿名函数
  6. n = n + i
  7. ss = ss + s
  8. return n, ss
  9. }
  10. }
  11. func main() {
  12. f := Bibao("A") //声明一个闭包
  13. fmt.Println(f(1, "a")) //11 Aa
  14. fmt.Println(f(1, "b")) //12 Aab
  15. }

闭包难以理解……….