为路由器写脚本,顺带学了一下lua.对闭包函数做个理解笔记

普通函数内部可以直接读取全局变量。如:

1
2
3
4
5
6
7
local n = 1
function f1( ... )
return n
end
print(f1()) --1

但普通函数内部却无法读取一个与自己不同作用域的局部变量。如:

1
2
3
4
5
6
7
8
9
10
function f1( ... )
local n = 1
return n
end
function f2( ... )
print(n)
end
f2() --nil

但是通过下列这种特殊的函数写法,就可以让一个函数读取一个与自己不同作用域的局部变量:

1
2
3
4
5
6
7
8
9
10
11
function f1( ... )
local n = 1
function f2( ... )
n = n + 1
return n
end
return f2
end
local result = f1()
print(result()) --2

在上面的代码中,函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1 就是不可见的。

既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,我们就可以在f1外部读取它的内部变量!
这种函数叫称之为闭包函数。

所以,如果要用一句话说明白闭包函数,那就是:>函数内在包含子函数,并最终return子函数。

而闭包函数的最大价值在于:我们可以在函数的外部(即子函数),直接读取该函数的局部变量。

再仔细研究,就会发现f1()函数就如同一个“类”,而其定义的局部变量就如同该“类”的全局变量;而子函数f2()函数,则如同这个“类”的方法,可以直接使用这个“类”的全局变量n。神奇吧?

现在总算明白什么是闭包函数了,虽然其实现很神奇,但闭包函数有什么用?

1、缓存:最显而易见的好处,就是可以实现数据缓存,我们可以把一个需要长期用到的变量设为闭包函数的局部变量,在子函数里面直接使用它。因此局部变量只定义初始化一次,但我们可以多次调用子函数并使用该变量。这比起我们在子函数中定义初始化变量,多次调用则多次初始化的做法,效率更高。闭包函数常见的一种用途就是,我们可以通过此实现计数功能。在闭包函数定义一个计数变量,而在子函数中对其进行++的操作。这样每次调用闭包函数,计数变量就会加1。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function f1( ... )
local n = 0
function f2( ... )
n = n + 1
return n
end
return f2
end
local count = f1()
print(count()) --1
print(count()) --2
print(count()) --3
print(count()) --4
print(count()) --5


2、实现封装:如同前面所说,闭包函数就如同一个“类”,只有在该闭包函数里的方法才可以使用其局部变量,闭包函数之外的方法是不能读取其局部变量的。这就实现了面向对象的封装性,更安全更可靠。