zoukankan      html  css  js  c++  java
  • Lua学习(4)——函数

    在Lua中函数的调用方式和C语言基本相同,如:print("Hello World")和a = add(x, y)。唯一的差别是,如果函数只有一个参数,并且该参数的类型为字符串常量或table的构造器,那么圆括号可以省略,如print "Hello World"和f {x = 20, y = 20}。
        Lua为面对对象式的调用也提供了一种特殊的语法--冒号操作符。表达式o.foo(o,x)的另一种写法是o:foo(x)。冒号操作符使调用o.foo时将o隐含的作为函数的第一个参数。
        Lua中函数的声明方式如下:

      function add(a)
            local sum = 0
            for i, v in ipairs(a) do
                sum = sum + v
            end
            return sum
        end
    

    1. 多重返回值(multiple results)

    Lua允许函数多个结果

    例如

    s,e = string.find("hello lua world","lua")
    
    function fun() 
        a="world" 
        b="hello" 
        return a,b 
    end
    
    i,j=fun()
    print(i,j)
    

     如果函数没有返回值或者没有足够多的返回值,那么Lua用nil来填充

    1 x,y,z=fun()
    2 z的值是nil

     如果一个函数调用不是一系列的表达式的最后一个元素,那么将只产生一个值:

    x,y=fun(),20
    -- x="hello" y=20
    --fun() 返回 2个值"hello" "world"

    强制返回一个元素加括号(fun())

    > function fun() a="hello" b="world" return a,b end
    > print((fun()))
    hello

    最后一个需要介绍的是Lua中unpack函数,该函数将接收数组作为参数,并从下标1开始返回该数组的所有元素。如:

    > print(unpack{10,20,30})
    10      20      30
    

     unpack函数一个重要用途体现在泛型调用机制中。泛型调用机制可以动态以任何实参来调用函数。

    关于unpack的使用请查看 http://www.cnblogs.com/corolla/p/3811793.html

     1 function fun(a,b) 
     2     if a>b then 
     3         print(a)
     4     else 
     5        print(b) 
     6     end 
     7 end
     8 tb={1,2}
     9 fun(unpack(tb))
    10 2

     当tb表的数量过多时

    tb={1,2,4}
    fun(unpack(tb))
    2

    2. 变长参数

    Lua中的函数可以接受不同数量的实参,查看以下例子:

    function add(...)
            local s = 0
            for i,v in ipairs(...) do
                    s = s+v
            --      print(v)
            end
            return s
    end
    tb={1,2,3,4}
    print(add(tb))

     local a,b = ...类似于一个具有多重返回值的函数 

    > function fun(...) local a,b=... print(a,b) end 
    > fun(2,4) 2 4

     访问变长...参数,使用select函数,访问{...}和访问table一样。select{"#",...}取参数总数,local arg = select{i,...}访问第i个。遍历的例子如下

    function fun(...)
            local s=0
            n = select("#",...)
            for i=1, n do
                    local arg=select(i,...)
                    s = s+arg
            end
            return s
    end
    
    tb={1,2,3,4}
    print(fun(unpack(tb)))

    3. 具名实参:

     Lua中的参数传递机制是具有“位置性”的,也就是调用函数时,实参和形参必须一一对应。Lua并不直接支持这种语法,但可以通过一种细微的改变来获取相同的效果。主要是将所有实参组织到一个table中,并将这个table作为唯一的实参传给函数。

     tb={old="temp.lua",new="new.lua"}
     function rename(arg)
       return os.rename(arg.old,arg.new) 
     end
     rename(tb)

     如果一个函数有大量的参数,其中大部分是可选的时候,具名参数传递的方法非常有用。

    深入理解函数

    Lua中函数是一种“第一类值”,它们具有的特定的词法域(Lexical  Scoping)

    “第一类值”表示Lua函数与其他的传统的值具有相同的权利。函数可以存储到变量中或table中。也可以作为实参传递给其他函数,也可以作为其他函数的返回值。

    “词法域”是值一个函数可以潜逃在另一函数中,内部的函数可以访问外部函数中的变量。

    在Lua中有一个容易混淆的概念是,函数与所有其他值一样都是匿名的,即他们都没有名称。函数名实际上是某函数的变量,与其他变量持有各种值是一个道理。

    > tb={p=print}
    > tb.p("hello world")
    hello world
    > print = math.sin  --print==sin函数
    > tb.p(print(1))
    0.8414709848079

    4. 闭合函数(closure)

    若将一个函数写在另一个函数之内,那么这个位于内部的函数便可以访问外部函数中的局部变量

    newCounter = function(add)
        local i = 0;
        counter = function()
            i = i + add
            return i
        end
        return counter
    end
    c1 = newCounter(1)
    print(c1())
    1
    print(c1())
    2
     
    • lua中的函数是“第一类值”,就是说函数和整数,字符串这些是一样的,都可以保存到变量中,看上面第一句的声明。
    • 初看上去,由于创建变量i的函数newCounter已经返回,所以之后每次调用匿名函数时,i都应是超出作用返回的。其实不然,Lua以closure概念处理这种情况,一个closure就是一个函数加上它访问的所有“非局部的变量”。上例中内部函数counter 的非局部变量就是i和参数add,不管c1访问多少次,都能取到这些非局部变量的值。
     

    5. 非全局函数

    6. 真确的尾调用(tail call)

     Lua函数有一个特点:那就是Lua支持“尾调用消除” :尾调用消除就是一种类似于goto的函数调用。当一个函数f末尾调用其他函数g时,称为“尾调用”。也就说,当调用完g之后,f函数没有其他代码需要执行。这种情况,程序也不需要保存任何关于改函数的栈(stack)信息了。lua语言的尾调用不消耗任何的栈空间。

    由于Lua函数尾调用不会消耗栈空间,所以一个程序可以拥有无限潜逃的尾调用。

    function f(x) g(x) end --不算,g(x)后需要舍弃临时结果
    return g(x)+1 --必须做一次加法
    return x or g(x) --必须调整为一个返回值
    
    正确的尾调用:
    return <function>(<args>)

    没有“尾调用消除”的话,每次调用都会创建一个新的栈层(stack level).

  • 相关阅读:
    TCP/IP协议详解
    linux高性能服务器编程--初见
    聚合类
    类class 2
    继承
    构造函数再探
    静态成员与友元
    MySQL图形工具SQLyog破解版
    MySQL注释符号
    数据库中多对多关系的中间表的命名规则
  • 原文地址:https://www.cnblogs.com/oldtrafford/p/3817395.html
Copyright © 2011-2022 走看看