原本函数在最开始的时候就实现了,但是后来发现了不少bug,都是由参数个数,返回值个数等引起的,比想象的要复杂一些。
lua中函数与闭包是紧密相连的。我们早在学习c或java的的时候,就认识了函数,学习诸如lua,python,js脚本语言的时候才听说闭包这个词。在很长一段时间内我对闭包的概念都不是很理解,后来才慢慢清晰。现在亲自实现脚本语言后,才真正明白闭包的含义。
简单一句话概括就是,函数是静态的代码,闭包是动态执行的指令。这个好像类似线程和进程的概念。为什么c或java里没有听说过闭包的概念,反而在脚本语言中才出现呢?这是因为c或java是编译型语言,而脚本语言大都是解释型语言。
c或java语言被执行前先要经过编译,涉及到函数时,其调用参数个数,类型,及返回值个数,类型必须和函数声明时一致,否则编译出错。而脚本语言是不需要编译的,直接运行。本身脚本语言最大的优点就是方便,灵活,没有类型检查,各种变量随意赋值。这就意味着涉及到函数时有很大的变数。不仅没有类型检查,而且参数调用个数也可以与函数声明时的不一致,即实参和形参不一致。脚本语言的函数还有个很赞的亮点就是可以返回多个值,如果用c来返回值多个值,就是返回一个结构体,还是有点复杂,脚本语言这点很爽有木有!
虽然脚本语言很灵活,用起来很爽,但是要苦了实现脚本语言编译器的人,当然也包括我了。怎么样处理函数调用参数个数,返回值个数不一致的问题?我们可以这样想,函数代码声明之后永远是不变的,而函数调用时却有不同的情形。一个函数可以被调用N次,每次的调用参数和实际返回值的个数可能不一样。例如下面的代码:
local f = function(a, b) return 10, a, b end
local a,b = f()
f(1)
local c = f(2,3) + 5
你看三种函数的调用却都不一样,第一个没有传入参数,需要两个返回值。第二个传入一个参数,不需要返回值。第三个传入了2个参数,只需要一个返回值。我们可以把这三个函数看作是函数的三个实例。
也就是说实例是动态的代码,函数是静态声明的代码。每当调用函数时,我们就生成一个新的实例,我们可以把这个实例叫做闭包,而函数则是闭包的原型,因为闭包是由他生成的。
每个闭包必须要保存其传入的参数个数和需要返回值的个数,而函数的这些属性是声明时就决定好了的,以后不会有变化。介绍了这些背景,下篇我们正式讲解函数的实现。