函数的作用是将相同功能的代码块独立出来,用户可以重复使用。

函数的定义

在Go语言中,函数使用func关键字来定义,基本格式如下:

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

其中:

  • 函数名:由字母、数字、下划线组成,不能以数字开头,推荐驼峰式命名方式。在同一个包里函数名不能同名;
  • 参数:参数由参数变量和参数类型组成,多个参数以, 隔开;
  • 返回值:返回值由返回值变量和返回值类型组成,多个返回值以,隔开;

例如:

  1. func sum(x int,y int)(sum int){
  2. return x +y
  3. }

说明:函数的参数和返回值是可选的。

函数的调用

定义好函数之后,我们可以通过函数名()的方式调用函数。

例如:

  1. package main
  2. import "fmt"
  3. func sum(x int, y int) (sum int) {
  4. return x + y
  5. }
  6. func main() {
  7. // 调用函数
  8. ret := sum(10, 20)
  9. fmt.Println(ret)
  10. }

注意:如果调用的函数有返回值,我们可以像上面例子中接收这个返回值,我们也可以不接收。

函数的其他定义方式

类型简写

如果函数的参数中相邻两个参数的类型相同,我们可以把前面的参数类型省略。如下:

  1. func f1(x, y int) (sum int) {
  2. return x + y
  3. }

如上即为x和y都是int类型。

返回值变量省略

上面介绍返回值包含返回值变量和返回值类型,其中的返回值变量可以省略。如下:

  1. func f1(x, y int) int {
  2. return x + y
  3. }

这两种的区别:如果在函数定义的时候写了返回值变量,我们在函数体中可以直接使用这个变量,而且在return的时候可以不写这个变量,如下:

  1. func f1(x, y int) (sum int) {
  2. sum = x + y
  3. return
  4. }

可变参数

可变参数是指函数的参数不固定,在Go语言中的可变参数通过在参数后面加... 来标识。

如下:

  1. func sum(x int, y ...int) int{
  2. sum := x
  3. for _, v := range y{
  4. sum += v
  5. }
  6. return sum
  7. }

注意

  • 可变参数必须放在参数的最后面;
  • 可变参数是一个切片,比如上面定义的y就是一个切片;

函数的进阶

变量的作用域

全局变量

在Go语言中定义在函数外部的变量即为全局变量,该变量在程序的整个生命周期都有效,函数中可以访问到全局变量。

该变量的定义必须有关键字var。如下:

  1. package main
  2. import "fmt"
  3. // 全局变量
  4. // 定义一个全局变量
  5. var a = 100
  6. func main() {
  7. fmt.Println(a) // 输出:100
  8. }

局部变量

在Go语言中,有两种局部变量:

  • 定义在函数内,函数内都可以使用;
  • 只在函数内某个代码块中使用,代码块执行完,该变量就失效了;

对于第一种,示例如下:

  1. package main
  2. import "fmt"
  3. // 全局变量
  4. // 定义一个全局变量
  5. var a = 100
  6. // 定义一个函数
  7. func f1() {
  8. b := 200
  9. fmt.Println(b)
  10. }
  11. func main() {
  12. fmt.Println(a) // 输出:100
  13. // 调用函数
  14. f1()
  15. }

对于第二种,示例如下:

  1. package main
  2. import "fmt"
  3. // 全局变量
  4. // 定义一个全局变量
  5. var a = 100
  6. // 定义一个函数
  7. func f2() {
  8. if a := 19; a > 10 {
  9. fmt.Println(a)
  10. } else {
  11. fmt.Println("No BB")
  12. }
  13. }
  14. func main() {
  15. fmt.Println(a) // 输出:100
  16. // 调用函数
  17. f2()
  18. }

注意:如果局部变量与全局变量重名,那么局部变量得优先级高于全局变量。

如下:

  1. package main
  2. import "fmt"
  3. // 全局变量
  4. // 定义一个全局变量
  5. var a = 100
  6. // 定义一个函数
  7. func f1() {
  8. a := 200
  9. fmt.Println(a) // 输出:200
  10. }
  11. func main() {
  12. fmt.Println(a) // 输出:100
  13. // 调用函数
  14. f1()
  15. }

函数类型与变量

函数类型

在Go语言中,可以用type关键字来定义函数类型。如下:

  1. type myFunc func(int,int) int

上面就定义了一个myFunc类型,它是一个函数类型,它接收两个int参数并返回一个int类型的返回值。

凡是满足这类条件的函数都是myFunc类型的函数,比如下面的addsub 函数都是myFunc类型的函数:

  1. func add(x, y int) int {
  2. return x + y
  3. }
  4. func sub(x, y int) int {
  5. return x - y
  6. }

那么就可以把addsub 赋值给myFunc的变量,如下:

  1. package main
  2. import "fmt"
  3. func sum(x, y int) int {
  4. return x + y
  5. }
  6. func sub(x, y int) int {
  7. return x - y
  8. }
  9. func main() {
  10. type myFunc func(int, int) int
  11. var test myFunc
  12. test = sum
  13. fmt.Println(test(1, 2))
  14. }

函数类型的变量

既然可以定义函数类型,那么就可以通过该类型来声明变量,这个变量可以进行赋值操作,这个赋值的变量须满足该类型的条件,如上。

高阶函数

函数作为参数

函数可以作为参数传递到其他函数中,如下:

  1. package main
  2. import "fmt"
  3. func f1(x, y int) int {
  4. return x + y
  5. }
  6. func f2(a, b int, f func(int, int) int) int {
  7. sum := f(a, b)
  8. return sum
  9. }
  10. func main() {
  11. ret := f2(1, 2, f1)
  12. fmt.Println(ret)
  13. }

f2的函数中定义了三个参数:abf。其中a,b就是普通的int类型的参数,f是一个函数参数,这个函数需要传入两个int类型的参数并返回一个int类型的返回值。

函数作为返回值

函数不仅可以作为参数,它还能作为返回值。如下:

  1. package main
  2. import "fmt"
  3. func f1(a, b int) int {
  4. return a + b
  5. }
  6. func f2(x, y int) func(int, int) int {
  7. fmt.Println(x + y)
  8. return f1
  9. }
  10. func main() {
  11. ret := f2(1, 2)
  12. ret2 := ret(3, 4)
  13. fmt.Println(ret2)
  14. }

如上,在函数f2中我们定义了一个返回值,其返回值的类型是函数,所以我们在调用完f2后,接收其返回值,我们可以再一次对这个返回值做函数调用。

匿名函数

在Go语言中,函数内部不能再像之前那样定义标准的函数了,只能定义匿名函数。所谓的匿名函数就是没有函数名的函数。如下:

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

由于匿名函数没有函数名,所以不能像普通函数那样调用。要运行匿名函数有以下两种方式。

第一种,用一个变量去接收匿名函数,然后通过变量来调用函数。如下:

  1. package main
  2. import "fmt"
  3. func main() {
  4. // 定义一个匿名函数,用变量去接收
  5. f1 := func(x, y int) int {
  6. return x + y
  7. }
  8. // 通过变量去调用执行函数
  9. ret := f1(1, 2)
  10. fmt.Println(ret)
  11. }

第二种,自动执行匿名函数。如下:

  1. package main
  2. import "fmt"
  3. func main() {
  4. // 定义一个匿名函数自动执行
  5. func(x, y int) {
  6. fmt.Println(x + y)
  7. }(1, 2)
  8. }

当然,如果这个匿名函数有返回值,而且要接收这个返回值,我们依然要用一个变量去接收它,如下:

  1. package main
  2. import "fmt"
  3. func main() {
  4. // 定义一个匿名函数自动执行
  5. ret := func(x, y int) int {
  6. return x + y
  7. }(10, 20)
  8. fmt.Println(ret)
  9. }

闭包

闭包,首先是一个函数,它是定义在函数内部的函数,它由于可以读取非它本身的外部变量,就称之为闭包。

由于在Go语言中函数内定义函数只能用匿名函数,所以在Go语言中,闭包就要充分利用匿名函数。

如下:

  1. package main
  2. import "fmt"
  3. func f(x int) func(int) int {
  4. return func(y int) int {
  5. return x + y
  6. }
  7. }
  8. func main() {
  9. f1 := f(1)
  10. ret := f1(2)
  11. fmt.Println(ret)
  12. }

上面例子中,函数f定义的函数作为返回值,所以在内部用到了匿名函数。f1变量获取到的就是返回的那个匿名函数,它里面引用了外部函数f的变量x ,这就形成了闭包。在f1的生命周期里,变量x会一直有效。

内部函数

内置函数 介绍
close 主要用来关闭channel
len 用来求长度,比如string、array、slice、map、channel
new 用来分配内存,主要用来分配值类型,比如int、struct。返回的是指针
make 用来分配内存,主要用来分配引用类型,比如chan、map、slice
append 用来追加元素到数组、slice中
panic和recover 用来做错误处理

递归函数

递归函数就是自己调用自己。常用的比如计算斐波拉契,阶乘等等。

例子:假如有n层台阶,一次可以走1个,也可以走2个,请问有几种走法

  1. package main
  2. import "fmt"
  3. func taijie(n uint) uint {
  4. if n == 1 {
  5. return 1
  6. }
  7. if n == 2 {
  8. return 2
  9. }
  10. return taijie(n-1) + taijie(n-2)
  11. }
  12. func main() {
  13. ret := taijie(5)
  14. fmt.Println(ret)
  15. }