1.在lua中,函数是一种第一类值,具有特定的词法域。
第一类值指函数可以储存到变量中或table中,可以作为实参传递,可以作为实参传递给其他函数,还可以作为其他函数的返回值
词法域指一个函数可以嵌套到另一个函数中,内部函数可以访问外部函数的变量
函数与所有其他值一样都是匿名的,当讨论一个函数时,实际上是在讨论一个持有某函数的变量。构造函数时,我们会将函数赋予全局变量,但在某些特殊情况中,仍会需要用到匿名函数,例如table.sort()
从技术上讲,Lua中只有closure, 而不存在“函数”。因为,函数本身就是一种特殊的closure。
(closure)闭合函数:
function newCounter() --在这段代码中,匿名函数访问了一个“非局部变量”i,该变量
local i = 0 --用于保持一个计数器。初看上去,由于创建变量i的函数已经返回
return function() --所以以后每次调用匿名函数时,i都应是超出了作用范围的
i = i + 1 --但其实不然,Lua会以closure的概念来正确处理这种情况。
return i --简单的讲,一个closure就是一个函数加上该函数所需访问
end --的所有局部变量。如果再次调用newCounter(),那么它会创建
end --一个新的局部变量i,从而也将得到一个新的closure。
c1 = newCounter()
print(c1()) --> 1
print(c2()) --> 2
c2 = newCounter()
print(c2()) --> 1
print(c1()) --> 3
在许多场合closure都是一种很有价值的工具。就像之前看到,它们可以作为sort这类高阶函数的参数。
closure对于那些创建其他函数的函数也很有价值,例如前例中的newCounter.
closure可以用于重新定义那些预定义的函数,如下面的例子利用closure限制文件的访问程序
local oldOpen = io.open
local access_OK = function(filename, mode)
<检查访问权限>
end
io.open = function(filename, mode)
if access_OK(filename, mode) then
return oldOpen(filename, mode)
else
return nil, "accsee denied"
end
end
2.函数存在table中的三种方法
lib = {}
lib.foo = function(x,y) return x+y end
lib.goo = function(x,y) return x-y end
lib = {
foo = function (x, y) return x+y end
goo = function (x, y) return x-y end
}
lib = {}
function lib.foo (x,y) return x+y end
function lib.goo (x,y) return x-y end
3.定义递归局部函数注意点
local fact = function(n)
if n == 0 then return 1
else return n*fact(n-1) --错误
end
end
编译到fact(n-1)时,局部的fact尚未定义完毕,此句调用的是一个全局的fact,可改为
local fact
fact = function(n)
...
end
4.尾调用消除
什么是尾调用:一个函数调用是另一个函数的最后一个动作
function f(x) return g(x) end
--当f调用完g后无事情可做,无需保存该函数的栈信息,称为尾调用消除
function foo(n)
if n > 0 then return foo(n-1) end --传入任何数字都不会造成栈溢出
end
以下不是尾调用:
function f(x) g(x) end --调用完g后还需丢弃g返回的临时结果
return g(x) + 1 --必须做一次加法
return x or g(x) --必须调整为一个返回值
return (g(x)) --必须调整为一个返回值
只有“return <func>(<args>)”这样的调用形式才算是一条尾调用,lua会在调用前对func和其参数求值
例如:return x[i].foo(x[j] + a*b, i+j) 是一条尾调用
5.迭代器
迭代器是一种可以遍历一种集合中所有元素的机制,在lua中,通常将迭代器表示为函数。
每调用一次函数,即返回集合中的下一个元素,closure对于迭代过程中的状态保持提供了极佳的支持
下面是一个简单的示例
function values(t)
local i = 0
return function() i = i+1;return t[i] end
end
--调用values产生一个迭代器,调用迭代器返回下一个值。泛型for在内部保存了迭代器函数。
下面看一个更高级的示例
function allwords()
local line = io.read() --当前行
local pos = 1 --一行中的当前位置
return function() --迭代器函数
while line do --若为有效的行内容就进入循环
local s,e = string.find(line, "%w+", pos)
if s then --是否找到一个单词
pos = e+1 --该单词的下一个位置
return string.sub(line, s, e) --返回该单词
else
line = io.read() --没有找到单词,尝试下一行
pos = 1 --在第一个位置上重新开始
end
end
return nil --没有其余行,遍历结束
end
end
for word in allwords() do
print(word)
end
上述迭代器在每个新的循环都创建一个新的closure,泛型for可用自身来保持迭代器状态