什么是闭包,Go语言闭包的用法
在 Go 语言里,匿名函数就可以被称为闭包。简单来说,闭包允许调用定义在其他环境下的变量,可使得某个函数捕捉到一些外部状态,如函数被创建时的状态。
用专业的语言表述,一个闭包继承了函数声明时的作用域,作用域内的变量会共享到闭包的环境中,因此,这些变量可以在闭包中被操作,直到被销毁。
闭包经常被用作包装函数,预先定义好一个或多个参数以用于包装,另一种常见的应用就是使用包来完成更加简洁的错误检查。
如果函数返回的闭包引用了该函数的局部变量(参数或函数内部变量):
闭包最初的目的是减少全局变量,在函数调用的过程中隐式地传递共享变量,有其有用的一面;但是这种隐秘的共享变量的方式带来的坏处是不够直接,不够清晰,除非是非常有价值的地方,否则一般不建议使用闭包。
对象是附有行为的数据,而闭包是附有数据的行为,类在定义时已经显式地集中定义了行为,但是闭包中的数据没有显式地集中声明的地方,这种数据和行为耦合的模型不是一种推荐的编程模型,闭包仅仅是锦上添花的东西,不是不可缺少的。
运行结果如下:
如果函数返回的闭包引用的是全局变量,则多次调用该函数返回的多个闭包引用的都是同一个全局变量。同理,调用一个闭包多次引用的也是同一个全局变量。此时如果闭包中修改了全局变量值的逻辑,则每次闭包调用都会影响全局变量的值。使用闭包是为了减少全局变量,所以,闭包引用全局变量不是好的编程方式。
用专业的语言表述,一个闭包继承了函数声明时的作用域,作用域内的变量会共享到闭包的环境中,因此,这些变量可以在闭包中被操作,直到被销毁。
闭包经常被用作包装函数,预先定义好一个或多个参数以用于包装,另一种常见的应用就是使用包来完成更加简洁的错误检查。
什么是闭包
闭包是由函数及其相关引用环境组合而成的实体,一般通过在匿名函数中引用外部函数的局部变量或包全局变量构成。闭包=函数+引用环境闭包对闭包外的环境引入是直接引用,编译器检测到闭包,会将闭包引用的外部变量分配到堆上。
如果函数返回的闭包引用了该函数的局部变量(参数或函数内部变量):
- 多次调用该函数,返回的多个闭包所引用的外部变量是多个副本,原因是每次调用函数都会为局部变量分配内存。
- 用一个闭包函数多次,如果该闭包修改了其引用的外部变量,则每一次调用该闭包对该外部变量都有影响,因为闭包函数共享外部引用。
闭包最初的目的是减少全局变量,在函数调用的过程中隐式地传递共享变量,有其有用的一面;但是这种隐秘的共享变量的方式带来的坏处是不够直接,不够清晰,除非是非常有价值的地方,否则一般不建议使用闭包。
对象是附有行为的数据,而闭包是附有数据的行为,类在定义时已经显式地集中定义了行为,但是闭包中的数据没有显式地集中声明的地方,这种数据和行为耦合的模型不是一种推荐的编程模型,闭包仅仅是锦上添花的东西,不是不可缺少的。
在闭包内部修改引用的变量
闭包对它作用域上部的变量可以进行修改,修改引用的变量会对变量进行实际修改,例如:package main import ( "fmt" ) func main() { //准备一个字符串 str := "Apple" //创建一个匿名函数 foo := func() { //匿名函数中访问str str = "Orange" } //调用匿名函数 foo() fmt.Println(str) }在以上代码中:
- 第 7 行,准备一个字符串,用于修改。
- 第 9 行,创建一个匿名函数。
- 第 11 行,在匿名函数中并没有定义 str,str 的定义在匿名函数之前,此时,str 就被引用到了匿名函数中,形成了闭包。
- 第 14 行,执行闭包,此时 str 发生修改,变为 Orange。
运行结果如下:
Orange
如果一个函数调用返回的闭包引用修改了全局变量,则每次调用都会影响全局变量。如果函数返回的闭包引用的是全局变量,则多次调用该函数返回的多个闭包引用的都是同一个全局变量。同理,调用一个闭包多次引用的也是同一个全局变量。此时如果闭包中修改了全局变量值的逻辑,则每次闭包调用都会影响全局变量的值。使用闭包是为了减少全局变量,所以,闭包引用全局变量不是好的编程方式。