一个封闭的使用环境结合在一起的功能。该函数通常是在另一个函数内部定义的匿名函数。环境是包围函数的词法范围(函数的词法范围的非常基本的概念就是存在于函数括号之间的范围)。
func g() { i := 0 f := func() { // 匿名功能 fmt.Println("f called") } }
在f另一个函数(如)中定义的匿名函数(如)的主体内g,变量存在于两者的范围内,f并且g可以访问。但是,正是此范围的范围g构成了闭包的环境部分(函数部分为f),因此,对g范围内的变量所做的更改保留了它们的值(即,在调用之间环境仍然存在f)。
考虑以下功能:
func NaturalNumbers() func() int { i := 0 f:= func() int { // f是闭包的功能部分 i++ return i } return f }
在上述定义中,NaturalNumbers具有内函数f,其NaturalNumbers返回。在内部f,正在访问i范围内定义的变量NaturalNumbers。
我们从NaturalNumbers这样获得一个新功能:
n := NaturalNumbers()
现在n是一个关闭。这是一个函数(由定义f),还具有一个关联的环境(范围为NaturalNumbers)。
对于n,环境部分仅包含一个变量:i
由于n是一个函数,因此可以称为:
fmt.Println(n()) // 1个个 fmt.Println(n()) // 2 fmt.Println(n()) // 3
从上面的输出中可以明显看出,每次n调用都会递增i。i从0开始,每个对nexecute的调用i++。
i两次调用之间保留的值。即,作为封闭的一部分的环境持续存在。
NaturalNumbers再次调用将创建并返回一个新函数。这将在中初始化一个新i的NaturalNumbers。这意味着新返回的函数形成另一个闭包,该闭包具有与函数相同的部分(still f),但具有全新的环境(新初始化的i)。
o := NaturalNumbers() fmt.Println(n()) // 4 fmt.Println(o()) // 1个个 fmt.Println(o()) // 2 fmt.Println(n()) // 5
二者n并o是含有相同功能的部分(这使他们相同的行为)关闭,但不同的环境。因此,使用闭包允许函数访问持久性环境,该环境可用于在调用之间保留信息。
另一个例子:
func multiples(i int) func() int { var x int = 0 return func() int { x++ // 倍数的参数(这里是i)也形成 // 环境的一部分,并被保留 return x * i } } two := multiples(2) fmt.Println(two(), two(), two()) // 2 4 6 fortyTwo := multiples(42) fmt.Println(fortyTwo(), fortyTwo(), fortyTwo()) // 42 84 126