1.函数申明

1.1 声明语法

func funcName( param type ) (output1 type1, output2 type2) {
//这里是处理逻辑代码
//返回多个值
return value1, value2
}

1.2 语法解析

  • func: 函数关键字,
  • funcName: 指函数名,在同一个包内,函数不能重名。
  • param: 参数列表;参数列表指定的是参数类型、顺序及参数个数,函数可以不包含参数也可以不包含。
  • output1 type1, output2 type2: 返回值列表,Go语言的函数可以返回多个值。返回值可以是返回数据的数据类型,也可以是变量名+变量类型的组合。

2. 参数接收

2.1 参数类型简写

在参数列表中,如果有多个参数变量,则以逗号分隔;如果相邻变量是同类型,则可以将类型省略。

使用示例
package main
import "fmt"
func main() {
//total,desc := noUseShortParam(3,4,"求和")
total,desc := useShortParam(3,4,"求和")
fmt.Printf("total: %d desc: %s" , total,desc)
}

// 参数不简写的用法,并且使用返回: 变量名+变量类型组合
func noUseShortParam(a int , b int, str string) (total int, desc string) {
// 返回中已经声明返回变量名称,这里可以直接使用
total = a + b
desc = fmt.Sprintf("%s: %d + %d = %d",str,a,b,total)
return total,desc
}

// 参数简写的用法
func useShortParam(a,b int, str string) (int, string) {
// 返回中只声明返回变量类型,这里需要声明变量后才能使用
total := a + b
desc := fmt.Sprintf("%s: %d + %d = %d",str,a,b,total)
return total,desc
}

输出:

// 输出:
total: 7 desc: 求和: 3 + 4 = 7

2.2 可变参数

arg ...type: 告诉Go这个函数接受不定数量的参数。在函数体中,变量arg是一个int的slice(切片)。

使用示例
package main
import "fmt"
func main() {
uncertain(3,4,5,6,7)
}
// 接收不固定参数
func uncertain( number ...int) int {
fmt.Printf("类型: %T 值: %v \n", number,number)
var total int
for _,val := range number {
total += val
}
fmt.Printf("总和: %v",total)
return total
}
/* 输出:
类型: []int 值: [3 4 5 6 7]
总和: 25
*/

注意事项:

  • 一个函数最多只能有一个可变参数。
  • 若参数列表中还有其他类型参数,则可变参数写在所有参数的最后

3.变量作用域

3.1 定义介绍

作用域是变量、常量、类型、函数的作用范围。

局部变量: 在函数体内声明的变量称为局部变量,它们的作用域只在函数体内,其生命周期同所在的函数。参数和返回值变量也是局部变量。

**全局变量:**在函数体外声明的变量称为全局变量,全局变量可以在整个包甚至外部包(被导出后)使用。全局变量的生命周期同main()

全局变量可以在任何函数中使用。Go语言程序中全局变量与局部变量名称可以相同,但是函数内的局部变量会被优先考虑。

3.2 使用示例

package main

import "fmt"

// 声明全局变量
var a int = 100
var b int = 200

func main() {
// 在main函数内定义局部变量a,局部变量a会覆盖全局变量a
a := 50
fmt.Printf("a 的变量值 = %d,此时的a为局部变量 \n" , a)
fmt.Printf("b 的变量值 = %d \n" , b)
add := test(a,b)
fmt.Printf("add = %d \n" , add)

}
func test(a int, b int) int{
return a + b
}

输出:

a 的变量值 = 50,此时的a为局部变量 
b 的变量值 = 200
add = 250

4.函数类型

在Go语言中,函数也是一种类型,可以和其他类型(如int32、float等等)一样被保存在变量中。

在Go语言中可以通过type来定义一个自定义类型。函数的参数完全相同(包括参数类型、个数、顺序),函数返回值相同。

4.1 使用示例

示例1: 不声明函数类型

package main

import (
"fmt"
"strings"
)

func main() {
res := testFunc("hello,word! go is best language!!", funcParam)
fmt.Println("结果: " + res)
}

// 定义一个函数,接收字符串和函数类型: f func(string)string
func testFunc(str string, f func(string)string) string {
return f(str)
}

// 定义一个函数
func funcParam(str string) string {
result := ""
for i, val := range str {
if i % 2 == 0 {
// 偶数位置转成大写
result += strings.ToUpper(string(val))
} else {
// 奇数位置转成小写
result += strings.ToLower(string(val))
}
}
return result
}

示例2: 声明函数类型

package main

import (
"fmt"
"strings"
)
// 先声明一个函数类型
type strConvert func(string)string
func main() {
res := testFunc("hello,word! go is best language!!", funcParam)
fmt.Println("结果: " + res)
}

// 定义一个函数,接收字符串和函数类型: strConvert
func testFunc(str string, f strConvert) string {
return f(str)
}

// 定义一个函数
func funcParam(str string) string {
result := ""
for i, val := range str {
if i % 2 == 0 {
// 偶数位置转成大写
result += strings.ToUpper(string(val))
} else {
// 奇数位置转成小写
result += strings.ToLower(string(val))
}
}
return result
}

5.匿名函数

Go语言支持匿名函数,匿名函数没有函数名,只有函数体,函数可以作为一种类型被赋值给变量,匿名函数也往往以变量方式被传递。

5.1 语法

func(参数列表)(返回值列表){
// 函数体
}

5.2 使用示例

1. 调用匿名函数
package main
import "fmt"
func main() {
// 定义一个匿名函数
addFunc := func(a,b int)int{
return a + b
}
// 调用匿名函数
add := addFunc(10,5)
fmt.Printf("add = %d",add)
}
// 输出: add = 15
2.匿名函数当参数
package main
import "fmt"
func main() {
// 定义一个匿名函数,作为变量
addFunc := func(a,b int)int{
return a + b
}
// 在定义一个匿名函数接收匿名函数作为参数;
// 下面代码,相当于先定义匿名函数f,然后在调用匿名函数f(...)
total := func(a,b int,f func(int,int) int) int {
return f(a,b)
}(10,20,addFunc)
fmt.Printf("返回结果 : %d",total)
}
// 输出: 返回结果 : 30

6.递归函数

6.1 概念

在函数内部,可以调用其他函数。如果一个函数在内部调用自身,那么这个函数就是递归函数。

递归函数必须满足以下两个条件:

  • 在每一次调用自己时,必须是(在某种意义上)更接近于解。
  • 必须有一个终止处理或计算的准则。

6.2 使用示例

实现阶乘:n!=1×2×3×...×n

package main

func main() {
factorial(10)
}
// 递归实现num的阶乘
func factorial(num int) int {
if num == 0 {
return 1
}
res := num * factorial(num-1)
return res
}

6.3 使用注意事项

使用递归函数需要注意防止栈溢出。在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层,每当函数返回,栈就会减一层。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。