函数
函数是组织好的、可重复使用的、用于执行指定任务的代码块。
在 Go 中,函数是"一等公民"(First-Class Citizen),这意味着函数与其他数据类型一样,处于平等地位,可以赋值给其他变量,也可以作为参数传入另一个函数,或者作为别的函数返回值。
函数声明
函数声明以关键字 func 开始,声明后通过函数名这个标识符来使用函数。
func swap(x int, y int) (int, int) {
return y, x
}
2
3
参数列表紧接在函数名后面,用一个小括号包裹。它使用逗号作为参数分隔符,参数名在前,参数类型在后,使得 Go 代码更容易阅读。
返回值列表紧接在参数列表后面,两者之间用一个空格隔开,用来声明返回值类型。也可以提前在返回值列表中声明变量,然后在函数体中为变量赋值。通过这种方式,可以省略 return 语句后的变量列表。如果函数没有返回值,则返回类型可以省略。
大括号内是函数体,函数的具体实现逻辑都放在这里。
当多个参数属于同一类型时,可在最后一个参数之后声明该类型就行:
func swap(x, y int) (int, int) {
return y, x
}
2
3
在返回值列表中声明变量,可以简化函数的返回值处理:
func swap(x, y int) (b, a int) {
a = x
b = y
return
}
2
3
4
5
参数
函数分为声明与使用两个阶段,在不同阶段,参数的称谓也不同。在函数声明阶段,把参数列表中的参数叫做形式参数(Parameter,简称形参,就像占位符);而在函数实际调用时传入的参数被称为实际参数(Argument,简称实参)。
当实际调用函数时,实参会传递给函数,并和形参逐一绑定,编译器会根据各个形参的类型与数量,来检查传入的实参类型与数量是否匹配。只有匹配,程序才能继续执行函数调用,否则编译器就会报错。
值传递
所有参数都是值传递。所谓值传递,是指在调用函数时,将实参的值复制一份,传递给形参作为函数的输入。在函数内部修改形参的值不会影响到原始实参的值。
不过有两个例外,当形参为接口类型或者可变参数时,简单的值传递就不能满足要求了,这时 Go 编译器会介入:
- 对于接口类型的形参,Go 编译器会把传递的实参赋值给对应的接口类型形参
- 对于可变参数的形参,Go 编译器会将零或多个实参按一定形式转换为对应的可变形参
可变参数通过在参数名后加...来标识,通常作为函数的最后一个参数:
func add(i ...int) int {
total := 0
for _, v := range i {
total += v
}
return total
}
func main() {
println(add(1, 2, 3)) // 6 通过函数名()的方式调用函数
}
2
3
4
5
6
7
8
9
10
11
匿名函数
匿名函数(也叫函数字面值)就是没有名字的函数,由于没有函数名,就没办法像普通函数那样调用,所以匿名函数需要保存到某个变量或者作为立即执行函数。
func main() {
// 定义一个匿名函数,保存到变量
f := func(a, b int) int {
return a + b
}
r := f(1, 2) // 通过变量调用匿名函数
fmt.Println(r) // 3
// 定义匿名函数的同时调用,返回结果
r2 := func(a, b int) int {
return a + b
}(1, 2) // 自执行函数,匿名函数定义完加()直接执行
fmt.Println(r2)
// 直接定义,直接调用,直接返回
fmt.Println(func(a, b int) int {
return a + b
}(1, 2))
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
闭包
在一个函数内部定义了另一个函数,并且内部函数引用了外部函数的变量,那么这个内部函数和其引用的外部变量一起构成了一个闭包。这意味着闭包函数可以访问并操作其封闭范围内的变量,即使这些变量已经超出了其作用域,也可以在闭包函数中被访问和修改。
func outer() func() int {
count := 0 // 外部变量
// 内部函数
inner := func() int {
count++
return count
}
return inner
}
func main() {
// 调用外部函数返回内部函数,内部函数引用其外部作用域中的变量,此时next就是一个闭包
next := outer()
// 调用内部函数,它能够访问和修改外部函数的变量
fmt.Println(next()) // 1
fmt.Println(next()) // 2
fmt.Println(next()) // 3
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
因为匿名函数需要保留外部作用域的变量引用,所以匿名函数都是闭包的。
回调函数
回调函数(Callback Functions)是指一个函数被作为参数传递给另一个函数,并且在某个事件发生或条件满足时由另一个函数调用。回调函数常用于异步编程、事件驱动编程或者在某些条件下执行特定的逻辑。
func updateDB(cb func()) {
fmt.Println("更新数据库中...")
fmt.Println("数据库更新成功")
cb()
}
func main() {
fmt.Println("主线程开始运行...")
updateDB(func() {
fmt.Println("回调函数执行完毕,数据库关闭")
})
fmt.Println("主线程结束运行...")
}
2
3
4
5
6
7
8
9
10
11
12
13