直到我去写它时,我依然没有掌握函数闭包(Closure)的用法。

在函数式编程中,函数闭包指的是定义的函数(无论是不是匿名函数),都可以捕获环境中的变量(复制环境变量并与自身绑定,值拷贝或者引用拷贝都是语言的细节问题),并利用捕获到的变量改变函数的行为。

一个很朴素的想法就会从我们心底冒出:“如果要改变函数的行为,为什么不通过函数传参的方式改变,而是要通过捕获环境变量的方式?”。这是因为函数参数对于函数行为的影响发生在函数调用时;而捕获变量对于函数行为的影响发生在函数定义时。这是两种截然不同的语义。如果我们不使用闭包,但是希望函数的行为按照其“定义时”的变量而改变,那么就需要保留其定义时的数据,并在函数调用的时候作为参数传递给函数。

如此看来,其实能与闭包相比较的,应该是面向对象思想中的私有数据类似。这是因为私有数据以可以看作是在实例创建时保存的数据,并且可以影响实例方法的行为,比如说一个可以指定从几开始计数的计数器,OOP 的实现方式如下:

class Counter:
    def __init__(self, start):
        self.start = start
 
    def increment(self):
        self.start += 1
        return self.start
 
counter = Counter(10) # 从 10 开始计数
print(counter.increment()) # 11

而函数闭包的实现方式如下:

def make_counter(start):
    def increment():
        nonlocal start
        start += 1
        return start
    return increment
 
counter = make_counter(10) # 从 10 开始计数
print(counter()) # 11

在这个例子中, increment 函数捕获了外围变量 start ,并将其绑定在自己身上,就像 OOP 中的 self.start 一样。

那么面对这种场景到底是该用 OOP 还是 Closure 呢?我没有想清楚这两者到底那种更加简洁易懂,不过可以肯定的是,两者是可以互相代替的,而且闭包对于函数式编程,是一种语义的补充。