lua深入理解函数

来源:互联网 发布:三星淘宝官方旗舰店 编辑:程序博客网 时间:2024/05/29 16:26

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()) --> 1print(c2()) --> 2c2 = newCounter()print(c2()) --> 1print(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 endlib.goo = function(x,y) return x-y endlib = {    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 endfunction 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) --错误    endend编译到fact(n-1)时,局部的fact尚未定义完毕,此句调用的是一个全局的fact,可改为local factfact = 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 = 0return function() i = i+1;return t[i] endend--调用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          --没有其余行,遍历结束    endend for word in allwords() do    print(word)end

上述迭代器在每个新的循环都创建一个新的closure,泛型for可用自身来保持迭代器状态

原创粉丝点击