模块 3 · 第 4 课(共 5)课程中的14/50~12 min
模块课程(4/5)
闭包和函数作为值
在 Go 中,函数是一流的值:它们可以分配给 变量,传递给其他函数,然后返回。 闭包是 捕获变量的函数文字(匿名) 定义它的环境。
函数字面量
一个没有名字的函数,内联编写。您立即调用它或 分配它:
Go
greet := func(name string) {
fmt.Println("ciao", name)
}
greet("Anna")
// invocata immediatamente:
func() { fmt.Println("subito") }()greet 的类型是 func(string)。
捕获环境:关闭
函数文字可以读取和修改中可见的变量 它的词法范围,即使在外部函数返回之后:
Go
func counter() func() int {
n := 0
return func() int {
n++
return n
}
}
c := counter()
fmt.Println(c(), c(), c()) // 1 2 3只要至少有一个闭包引用它,n 就“存在”。每次致电
counter() 创建一个新的、独立的 n。
关闭作为回调
一个非常常见的模式:
Go
nums := []int{3, 1, 2}
sort.Slice(nums, func(i, j int) bool {
return nums[i] < nums[j]
})闭包捕获 nums 并定义顺序。
函数作为参数
要接受函数作为参数,请写出其类型:
Go
func apply(nums []int, f func(int) int) []int {
out := make([]int, len(nums))
for i, n := range nums {
out[i] = f(n)
}
return out
}
double := func(x int) int { return x * 2 }
apply([]int{1, 2, 3}, double) // [2 4 6]如果签名变得难以阅读,请定义一个类型别名:
Go
type Transform func(int) int
func apply(nums []int, f Transform) []int { ... }尝试一下
锻炼#go.m3.l4.e1
尝试:0加载中...
定义返回闭包的 counter():每次调用闭包都会递增并返回一个内部计数器。
正在加载编辑器...
显示提示
`n` 必须在返回之前声明;闭包捕获了它。
3 次尝试后可用的解决方案
锻炼#go.m3.l4.e2
尝试:0加载中...
为 f 分配一个打印“ciao”的函数文字,然后调用它。
正在加载编辑器...
显示提示
语法:`f := func() { ... }` 然后是 `f()`。
3 次尝试后可用的解决方案
Quiz#go.m3.l4.e3
准备好这打印什么? (注意闭包范围)
Go
mk := func() func() int {
x := 0
return func() int { x++; return x }
}
a := mk()
b := mk()
fmt.Println(a(), a(), b())回顾
- 函数是一流的:可分配、可传递、可返回。
- 函数文字:
func(params) ret { ... },匿名。 - 闭包:捕获词法作用域的变量,使它们保持活动状态。
- 参数中的显式函数类型:
func(int) int。 - 从 Go 1.22 开始,每个 for 迭代都有自己的循环变量副本。