Lua支持闭包的语法特性:
1.函数是第一类型值:第一类型值表示函数与其他传统类型的值(例如数字和字符串类型)具有相同的权利。即函数可以存储在变量中,可以作为实参传递给其他函数,还可以作为其他函数的返回值。以下两种定义函数的方式是等价的:
local function f1()
print("Hello")
end
--等价于
local f1 = function()
print("Hello")
end
2.词法定界:Lua中函数可以访问函数之外定义的值,该值可以定义在其他函数内,也可以直接定义在文件之内。该值叫做此函数的非局部变量或upvalue。通过下面例子可以看出函数可以对非局部变量的正确访问。
--f1访问未被定义在函数中的num
local num = 0
local function f1()
print(num)
end
f1()--输出0
--f3访问被定义在f2函数中的count
local function f2()
local count = 5
local function f3()
print(count)
end
f3()
end
f2()--输出5
3.闭包概念:Lua函数在多次调用时,可以正确访问他上次使用的非局部变量的值,这样的语法特性叫闭包。
广义来说,只要用到了外部定义的变量的函数,就使用了闭包特性。
通过下面例子可以看出函数多次调用时,上次使用的非局部变量的值得以保留。
--f1访问未被定义在函数中的num
local num = 0
local function f1()
num = num + 1
print(num)
end
for i=1,3,1 do
f1()--输出1,2,3
end
--f3访问被定义在f2函数中的count
local function f2()
local count = 5
local function f3()
count = count + 1
print(count)
end
for i=1,3,1 do
f3()--输出6,7,8
end
end
f2()
4.闭包应用:(只要出现了使用非局部变量的函数,就用了闭包)
4.1 在返回值是函数的函数中起到作用,比如创建迭代器,示例:
local function myIpairs(t)
local index = 0
local function f1()
index = index + 1
return index, t[index]
end
return f1
end
local color = {"red","blue","yellow","orange","black"}
local iter = myIpairs(color)
while true do
local k,v = iter()
if v then
print(k,v)
else
break
end
end
4.2 作为高阶函数(比如table.sort)的参数,且需要访问外部定义的变量。
local names = {"Peter", "Paul", "Mary"}
local grades = {Peter = 8, Paul = 7, Mary = 10}
for k,v in ipairs(names) do
print(v)
end
table.sort(names, function(n1,n2)
return grades[n1] > grades[n2]--grades为非局部变量,使用闭包
end)
print("--- after sort ---")
for k,v in ipairs(names) do
print(v)
end
4.3 用来重新定义函数,重定义时需要使用原来的函数。
local str = "galaxy"
local oldLen = string.len
function string.len(str)
local len = oldLen(str)--oldLen为非局部变量,使用闭包
print(str .. " length: " .. len)
return len
end
local len = string.len(str)--打印出galaxy length: 6
面试环节
问:Lua中闭包的概念是什么?
答:举例来说,有一对有嵌套关系的函数,外包函数叫f1,内嵌函数叫f2,f1内f2外定义一个局部变量a,a叫做f2的非局部变量,每次调用f2时不会重置a的语法特性叫做闭包。闭包可以用来创建迭代器,作为高阶函数的参数以及重新定义已存在的全局函数等作用。