Go 函数
定义函数
使用 func 关键词,第一个括号里面定义参数类型以及参数的标识符,第二个括号里面定义返回值类型。
func print(contents string) (int, error) {
//打印字符串并返回打印的字节数。
return fmt.Println(contents)
}
函数特性
- 支持不定参。
- 支持多返回值。
- 支持命名返回参数。
- 不支持嵌套,同一个包内不能有两个相同名字的函数。
- 不支持重载。
- 不支默认参数。
- 在 Go 中,函数也是一种类型,可以作为方法的入参或者返回结果。
- 支持匿名函数和闭包。
其中先简单了解一下基本的特性。
支持不定参
如下,print 函数有一个可以接受多个 string 入参。
和 JAVA 里面的不定参类似,这其实相当于是接受一个 srting 类型的数组,但是这样的入参类型只能定义在函数的最后面。
func print(contents ...string) (int, error) {
//打印字符串并返回打印的字节数。
return fmt.Println(contents)
}
func main() {
fmt.Println(print("11", "22"))
}
------------------------------------------------------
[11 22]
8 <nil>
支持多返回值和命名返回参数
上面的例子就是一个多返回值的函数,同时我们还能命名函数返回值。
返回的时候直接用 retun ,函数会自动将 count 和 err 返回回去。
func print(contents ...string) (count int, err error) {
//接收打印的字节数和异常
count,err = fmt.Println(contents)
return
}
func main() {
fmt.Println(print("11", "22"))
}
------------------------------------------------------
[11 22]
8 <nil>
不支持嵌套,不支持重载
以下代码都提示异常
文件①:/demo/demo_lib1.go
package main
import (
"fmt"
)
//提示异常: other declaration of print
func print(sss int, contents ...string) (count int, err error) {
//打印字符串并返回打印的字节数。
count, err = fmt.Println(contents)
return
}
文件②:/demo/demo_main.go
package main
import (
"fmt"
)
//提示异常: other declaration of print
func print(contents ...string) (count int, err error) {
//打印字符串并返回打印的字节数。
count, err = fmt.Println(contents)
return
}
func main() {
fmt.Println(print2("11", "22"))
}
高阶函数
上面我们提到,在 Go 中,函数可以作为另一个函数的入参或者返回结果。而以函数作为参数或者返回值的函数就称为高阶函数。
高阶函数的条件,满足其一即可:
- 使用其他函数作为入参
- 把其他函数作为返回结果
例如:
下面的 calc 函数和 retFunc 函数都是高阶函数。
type mathFunc func(x, y int) int
func calc(x int, y int, mf mathFunc) (int, error) {
if mf == nil {
return 0, errors.New("invalid operation")
}
return mf(x, y), nil
}
func retFunc() mathFunc {
return func(x, y int) int {
return x + y
}
}
闭包
什么是闭包
闭包是可以包含自由变量的代码块,这些变量不在这个代码块内或者任何全局上下文中定义,而是在定义代码块的环境中定义。要执行的代码块为自由变量提供绑定的作用域。
用代码来解释
type mathFunc func(i int) int
func operate2() mathFunc {
sum := 0
return func(j int) int {
sum += j
return sum
}
}
其中 operate2 函数中返回的这个匿名函数,就形成了一个闭包。
闭包中使用到了自由变量 sum ,这个 sum 是闭包函数所处函数环境中定义的,可以说匿名函数的功能被绑定在了变量 sum 上。
addBase := operate2(1) //addBase 为所有传入的 int 加 1
fmt.Println(addBase(2))
-----------------------------
3
闭包的作用
- 延迟动态生成程序逻辑,我们可以根据需要生成功能不同的函数。
- 缩小变量作用域,减少对全局变量的污染
在上面的例子中,我们其实实现了一个累加器,如果我们定义的是全局变量 sum ,有可能会被其他操作污染,而且当我们需要实现很多个累加器时,我们就需要定义很多个全局变量 sum 1…n。
但是我们使用闭包的方式,将累加值定义在函数中,缩小其作用域,使每个函数有自己独立的累加值,避免了累加值被其他操作污染的情况。