• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    Lua中的函数(function)、可变参数、局部函数、尾递归优化等实例讲解

    一、函数

    在Lua中,函数是作为"第一类值"(First-Class Value),这表示函数可以存储在变量中,可以通过参数传递给其他函数,或者作为函数的返回值(类比C/C++中的函数指针),这种特性使Lua具有极大的灵活性。
     
    Lua对函数式编程提供了良好的支持,可以支持嵌套函数。
     
    另外,Lua既可以调用Lua编写的函数,还可以调用C语言编写的函数(Lua所有的标准库都是C语言写的)。
     
    定义一个函数

    复制代码 代码如下:

    function hello()
    print('hello')
    end

    hello函数不接收参数,调用:hello(),虽然hello不接收参数,但是还可以可以传入参数:hello(32)
     
    另外如果只传递一个参数可以简化成functionname arg的调用形式(注意数值不行)

    复制代码 代码如下:

    > hello '3'
    hello
    > hello {}
    hello
    > hello 3
    stdin:1: syntax error near '3'

     
    另外对变量名也不适用
    复制代码 代码如下:

    > a = 21
    > print a
    stdin:1: syntax error near 'a'

     
    另外,Lua函数不支持参数默认值,可以使用or非常方便的解决(类似Javascript)
    复制代码 代码如下:

    > function f(n)
    >> n = n or 0
    >> print(n)
    >> end
    > f()
    0
    > f(1)
    1

    Lua支持返回多个值,形式上非常类似Python:

    复制代码 代码如下:

    > function f()
    >> return 1,2,3
    >> end
    > a,b,c = f()
    > print(a .. b .. c)
    123

     
    函数调用的返回值可以用于table:
    复制代码 代码如下:

    > t = {f()}
    > print(t[1], t[2], t[3])
    1        2        3
     
    可见,f()返回的三个值分别称为table的3个元素,但是情况并不总是如此:
    复制代码 代码如下:

    > t = {f(), 4}
    > print(t[1], t[2], t[3])
    1        4        nil

    这次,f()返回的1,2,3只有1称为table的元素;
    复制代码 代码如下:

    > t = {f(), f()}
    > print(t[1], t[2], t[3], t[4], t[5])
    1        1        2        3        nil

     
    总之:只有最后一项会完整的使用所有返回值(假如是函数调用)。
     
    对于无返回值的函数,可以使用(f())的形式强行返回一个值(nil)
    复制代码 代码如下:

    > function g()
    >> end
    > print(g())
     
    > print((g()))
    nil

    实际上,(f())形式的调用返回一个且只返回一个值
    复制代码 代码如下:

    > print((f()))
    1
    > print(f())
    1        2        3

    二、变长参数

    Lua支持编程参数,使用简单(借助于table、多重赋值)

    复制代码 代码如下:

    > function f(...)
    for k,v in ipairs({...}) do
    print(k,v)
    end
    end
    > f(2,3,3)
    1        2
    2        3
    3        3

    使用多重赋值的方式
    复制代码 代码如下:

    > function sum3(...)
    >> a,b,c = ...
    >> a = a or 0
    >> b = b or 0
    >> c = c or 0
    >> return a + b +c
    >> end
    > =sum3(1,2,3,4)
    6
    > return sum3(1,2)
    3

    通常在遍历变长参数的时候只需要使用{…},然而变长参数可能会包含一些nil;那么就可以用select函数来访问变长参数了:select('#', …)或者 select(n, …)

    select('#', …)返回可变参数的长度,select(n,…)用于访问n到select('#',…)的参数

    复制代码 代码如下:

    > =select('#', 1,2,3)
    3
    > return select('#', 1,2, nil,3)
    4
    > =select(3, 1,2, nil,3)
    nil        3
    > =select(2, 1,2, nil,3)
    2        nil        3

    注意:Lua5.0中没有提供…表达式,而是通过一个隐含的局部table变量arg来接收所有的变长参数,arg.n表示参数的个数;

    三、函数式编程

    函数做一个First-Class Value可以赋值给变量,用后者进行调用

    复制代码 代码如下:

    > a = function() print 'hello' end
    > a()
    hello
    > b = a
    > b()
    hello

    匿名函数
    复制代码 代码如下:

    > g = function() return function() print 'hello' end end
    > g()()
    hello

    函数g返回一个匿名函数;
     
    闭包是函数式编程的一种重要特性,Lua也支持
    复制代码 代码如下:

    > g = function(a) return function() print('hello'.. a); a = a + 1 end end
    > f = g(3)
    > f()
    hello3
    > f()
    hello4

    四、局部函数

    局部函数可以理解为在当前作用域有效的函数,可以用local变量来引用一个函数:

    复制代码 代码如下:

    > do
    >> local lf = function() print 'hello' end
    >> lf()
    >> end
    hello
    > lf()
    stdin:1: attempt to call global 'lf' (a nil value)
    stack traceback:
    stdin:1: in main chunk
    [C]: in ?

    需要注意的是,对于递归函数的处理

    复制代码 代码如下:

    > do
    local lf = function(n)
    if n = 0 then
    return
    end
    print 'hello'
    n = n -1
    lf(n)
    end
    lf(3)
    end
    hello
    stdin:8: attempt to call global 'lf' (a nil value)
    stack traceback:
    stdin:8: in function 'lf'
    stdin:9: in main chunk
    [C]: in ?

    而应该首先声明local lf, 在进行赋值
    复制代码 代码如下:

    do
    local lf;
    lf = function(n)
    if n = 0 then
    return
    end
    print 'hello'
    n = n -1
    lf(n)
    end
    lf(3)
    end
    hello
    hello
    hello

    Lua支持一种local function(…) … end的定义形式:
    复制代码 代码如下:

    > do
    local function lf(n)
    if n = 0 then
    return
    end
    print 'hello'
    n = n -1
    lf(n)
    end
    lf(3)
    end
    hello
    hello
    hello
    > lf(3)
    stdin:1: attempt to call global 'lf' (a nil value)
    stack traceback:
    stdin:1: in main chunk
    [C]: in ?

    五、尾调用

    所谓尾调用,就是一个函数返回另一个函数的返回值:

    复制代码 代码如下:

    function f()

    return g()
    end
     
    因为调用g()后,f()中不再执行任何代码,所以不需要保留f()的调用桟信息;Lua做了这样的优化,称为"尾调用消除",g()返回后,控制点直接返回到调用f()的地方。
     
    这种优化对尾递归非常有益,通常递归意味着调用桟的不断增长,甚至可能造成堆栈溢出;而尾递归提供了优化条件,编译器可以优化掉调用桟。
     
    下面的递归函数没有使用尾递归,而参数为大数时,堆栈溢出:
    复制代码 代码如下:

    > function f(n)
    >> if n = 0 then
    >> return 0
    >> end
    >> a = f(n-1)
    >> return n * a
    >> end
    > f(10000000000)
    stdin:5: stack overflow
    stack traceback:
    stdin:5: in function 'f'
    stdin:5: in function 'f'
    stdin:5: in function 'f'
    stdin:5: in function 'f'
    stdin:5: in function 'f'
    stdin:5: in function 'f'
    stdin:5: in function 'f'
    stdin:5: in function 'f'
    stdin:5: in function 'f'
    stdin:5: in function 'f'
    ...
    stdin:5: in function 'f'
    stdin:5: in function 'f'
    stdin:5: in function 'f'
    stdin:5: in function 'f'
    stdin:5: in function 'f'
    stdin:5: in function 'f'
    stdin:5: in function 'f'
    stdin:5: in function 'f'
    stdin:5: in function 'f'
    stdin:1: in main chunk
    [C]: in ?

    优化为尾递归
    复制代码 代码如下:

    function f(n, now)
    if n = 0 then
    return now
    end
     
    return f(n-1, now*n)
    end
    f(10000000000, 1)

    运行n久也无堆栈溢出;

    您可能感兴趣的文章:
    • Lua中的string库(字符串函数库)总结
    • Lua中的一些常用函数库实例讲解
    • Lua中的模块与module函数详解
    • Lua中的函数知识总结
    • Lua字符串库中的几个重点函数介绍
    • Lua的table库函数insert、remove、concat、sort详细介绍
    • Lua中的常用函数库汇总
    • Lua中的面向对象编程详解
    • Lua面向对象之类和继承
    • Lua面向对象之多重继承、私密性详解
    • Lua面向对象编程学习笔记
    • Lua中函数与面向对象编程的基础知识整理
    上一篇:Lua中的table浅析
    下一篇:Lua中的迭代器(iterator)浅析
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    Lua中的函数(function)、可变参数、局部函数、尾递归优化等实例讲解 Lua,中的,函数,function,可变,