很多编程语言已经是多年前发明的,随着编程思想的发展,逐步都会添加一些新的特性(理念)。其中一个重要的特性便是对函数的处理。这里我们不讨论函数与方法的区别,本文中函数即方法,方法即函数。
1.首先我们先明确一个概念:函数作为一等公民(first class citizen)。
以上来自于《Programming Language Pragmatics》,意思大概就是一等公民(一级状态)意味着可以作为函数参数、函数返回值,也可以赋值给变量
。举个例子,字符串就是一等公民。
明确了这个概念后,我们发现函数如果在编程语言中函数天然被设计成一等公民时,将极大的增加函数使用的灵活性,例如JavaScript中,函数就是一等公民。于是越来越多的语言开始吸收这个特性,分别在各自的领域中进行拓展,比如在Java中表现为Lambda,在Objective-C中表现为闭包(closure)。
综上,匿名函数、Lambda、闭包本质上是一个东西,即对函数是一等公民思想的应用在编程语言上的各自实现
。实际上大多数语言在后来发展中的各种新特性都是一样,都是对于某种思想应用在该语言上的实现。或者我们用一个更通用的词:语法糖
。
2.两个疑问
疑问1:为什么我们需要把函数作为参数?
通常来说,我们可以在外部直接定义一个函数,另一个函数内部直接调用即可,用不着非要作为参数传递。那作为参数传递是有什么用处?
作为参数,可以在传递时再定义其内容,即在这里函数实现是作为参数传递进来,而不是一开始定义好。
想想for循环,对于这个系统函数来说,这里的for循环中的函数体代码就是这样的思想,系统函数并不知道编写者需要做什么样的事情,所以系统只能把具体的函数实现放到for循环的这个函数体中,由用户去编写具体的内容,而系统只保证调用这函数。
function test (function A ){
A();
}
test((){
// Do something...
})
上面的例子中,test函数可以理解为系统for函数,给test函数传的参数即可以理解为for循环中的具体实现。
疑问2:在此之前,如何做到在使用时再定义函数具体实现的呢?
大多会使用一些设计模式去处理这样的问题。
比如Java中会使用接口(interface)、抽象类等,通过实现接口和继承去完成具体的实现。在Object-C中则是使用代理(delegate),通过实现代理去完成具体的实现。
其本质都是通过某些方式,交换了调用和定义的顺序,以达到可以动态改变函数实现的效果。