闭包(Closure) 是指一个函数与其相关的引用环境(变量集合)的组合。在 Go 中,函数是一等公民,因此可以在函数内部定义函数,并且这些内部函数可以访问外部函数的变量。当一个内部函数引用了外部函数的变量时,就形成了一个闭包。
闭包在实际编程中具有很多应用,例如可以用于实现函数工厂、延迟执行、状态保持等。
下面是一个简单的闭包示例:
package main
import "fmt"
func outerFunc() func() {
outerVar := "Hello"
// 内部函数是一个闭包,它引用了外部函数的变量 outerVar
innerFunc := func() {
fmt.Println(outerVar)
}
return innerFunc
}
func main() {
// 调用 outerFunc 返回内部函数 innerFunc,并将其赋值给变量 fn
fn := outerFunc()
// 调用 fn,它仍然可以访问 outerVar 变量
fn() // 输出:Hello
}
在上述示例中,我们定义了一个名为 outerFunc 的函数,它内部定义了一个名为 innerFunc 的函数。innerFunc 引用了 outerFunc 的局部变量 outerVar。
在 main 函数中,我们调用 outerFunc 并将返回的内部函数 innerFunc 赋值给变量 fn。然后,调用 fn,它仍然可以访问和打印 outerVar 的值。
通过闭包,innerFunc 可以访问 outerVar,即使 outerFunc 已经返回并且 outerVar 在其生命周期结束后仍然存在。
闭包的特性使得函数可以捕获和持有外部变量的状态,这对于某些编程模式和需求非常有用。
我们可以结合python的装饰器来理解golang闭包 下面是用python实现的一个的函数计时器装饰器
import time
def timer(func):
def func_in():
start_time = time.time()
func()
end_time = time.time()
spend_time = (end_time - start_time)/60
print("Spend_time:{} min".format(spend_time))
return func_in
@timer
def test():
# 这个函数是随便写的
list_a = []
for _ in range(10000000):
list_a.append(_)
print(len(list_a))
if __name__ == '__main__':
test()
我们可以使用golang来实现类似的功能,不过golang没有@timer的语法,但是这里只是为了帮助理解golang闭包的概念。
func Timer(f func()) func() {
return func() {
startTime := time.Now()
f()
endTime := time.Now()
spendTime := endTime.Sub(startTime).Minutes()
fmt.Printf("Spend_time: %.2f min\n", spendTime)
}
}
func main() {
// 示例函数
myFunc := func() {
time.Sleep(2 * time.Second)
fmt.Println("Hello, World!")
}
// 使用装饰器
decoratedFunc := Timer(myFunc)
decoratedFunc()
}
在上面的示例中,我们定义了一个Timer函数,它接受一个函数作为参数,并返回一个新的函数作为装饰后的函数。装饰后的函数会在调用原始函数之前和之后记录时间,并打印出运行时间。
在main函数中,我们定义了一个示例函数myFunc,它会休眠2秒并打印一条消息。然后,我们使用Timer装饰器将myFunc装饰成decoratedFunc,并调用decoratedFunc来执行装饰后的函数。运行程序后,你将看到输出的运行时间。