lua 函数

在Lua中,函数是对语句和表达式进行抽象的主要方法。既可以用来处理一些特殊的工作,也可以用来计算一些值。下面有3个例子,分别将函数当作一条语句;当作表达式(后面两个是一类)。

print(8*9,9/8)                  --> 72  1.125  
a = math.sin(3) + math.cos(10)   --> a = -0.69795152101659  
print(os.date())                 --> Sat Mar  9 12:14:08 2013  
函数如果带参数,那么就要用(arg1, arg2,...)括起来,如果没有参数,就写个空(),说明这是个函数调用
特例,如果函数只有一个参数,并且参数类型是字符串或者table,那么()可以省略,如下示例:
print "Hello World"   <==>   print("Hello World")  
dofile 'a.lua'        <==>   dofile('a.lua')  
print[[a multi-line   <==>   print([[a multi-line  
 message]]                    message]])  
f{x=10,y=20}         <==>   f({x=10,y=20})  
type{}                <==>   type({})  
Lua支持面向对象,操作符为冒号‘:’。o:foo(x) <==> o.foo(o,x)
Lua程序可以调用C语言或者Lua实现的函数。Lua基础库中的所有函数都是用C实现的。调用一个用C实现的函数,和调用一个用Lua实现的函数,二者没有任何区别。
Lua函数的定义语法比较常规,如下示例:
function add(a)  
    local sum = 0  
    for i,v in ipairs(a) do  
        sum = sum + v  
    end  
    return sum  
end  
函数的参数跟局部变量一样,用传入的实参来初始化,多余的实参被丢弃,多余的形参初始化为nil。示例如下:
function f(a,b) return a or b end  
f(3)        -- a=3,b=nil   传入的实参来初始化,多余的实参被丢弃
f(3,4)     -- a=3,b=4  
f(3,4,5)  -- a=3,b=4 (5被丢弃)  
虽然Lua可以处理这样的情况,但是不鼓励这种传入错误数量参数的函数调用,可能会使程序运行时有点小问题。不过,有些情况下,这个特性可以加以利用,例如下面示例的认参数:

1.多返回值
不同于常规函数,Lua的函数可以返回多个返回值。一些Lua中预定义的函数可以返回多个返回值。例如string.find函数,在string中匹配一个sub-string,string.find返回sub-string的起始位置和结束位置。利用多赋值语句来获取函数的多个返回值。
用Lua写的函数也可以返回多个返回值,如下示例,查找array中的最大值,并返回其位置和值

 多重返回值
查找数组中最大元素 并返回和它的位置
function maxminum(a)
     local mi = 1
     local m = a[mi]
     for i,val in ipairs(a) do
     	if  val >m then
     		mi = i; m = val
     	end
     end
     return m,mi
end
print(maxminum{4,6,19,26,3}) -- 26 4 
Lua会根据实际情况来使函数的返回值个数适应调用处的期望。
1)如果一个函数调用作为一条语句,所有的返回值都被丢弃
2)如果一个函数调用作为一个表达式,除了3)的情况,返回值只保留第一个
3)在多赋值,返回值作为实参来调用其他函数,table中,return语句中,这4种调用场景,如果函数调用作为其最后一个表达式,那么会保留所有的返回值,然后根据实际调用需要再纠正。
示例:
-- 多赋值,函数调用是最后一个表达式  
-- 多赋值  若是调用仅有的一个表达式 lua会保留其尽可能多的返回值  
-- 没有足够的返回时情况下用nil补缺
x,y = foo2()       print(x,y)      -- x="a",y="b"
x = foo2()         print(x)        -- x="a","b" is discarded
x,y,z = 10,foo2()  print(x,z)    -- x=10,y="a",z="b" 
x,y = foo0()       print(x,y)      -- x=nil,y=nil
x,y = foo1()       print(x,z = foo2()     print(x,z)    -- x="a",y="b",z=nil
-- 多赋值,函数调用不是最后一个表达式,因此返回值只保留第一个  
-- x,y = foo2(),20      print(x,y) -- x="a",y=20
-- x,y = foo0(),20,30  print(x,y)-- x=nil,y=20,30 被丢弃
-- 返回值作为实参来调用其他函数  
print(foo0())         -->  
print(foo1())         --> a  
print(foo2())         --> a b  
print(foo2(),1)      --> a 1  
print(1,foo2())      --> 1 a b   
print(foo2() .. "x")  --> 当foo2出现在一个表达式中,Lua将其返回值调整为1
-- table中  
t = {foo0()} -- t = {} (an empty table)  
t = {foo1()} -- t = {"a"}  
t = {foo2()} -- t = {"a","b"}  
  
-- table中,但是函数调用不是最后一个表达式  

t = {foo0(),foo2(),4} -- t[1] = nil,t[2] = "a",t[3] = 4  
print(unpack(t))

-- return语句中  
function foo (i)  
    if i == 0 then return foo0()  
    elseif i == 1 then return foo1()  
    elseif i == 2 then return foo2()  
    end  
end  
  
print(foo(1)) --> a  
print(foo(2)) --> a b  
print(foo(0)) -- (no results)  
print(foo(3)) -- (no results)  
用括号来强制返回值个数为一个

print((foo0())) --> nil  
print((foo1())) --> a  
print((foo2())) --> a  
因此,括号千万别乱用,尤其是return后的值,如果用了括号,那么就只返回一个值。


unpack 一个特殊函数 它接受数组做参数

print(unpack{10,30}) --> 10 20 30  
a,b = unpack{10,30} -- a=10,b=20,30 is discarded  
unpack的一个重要用法是泛型调用,提供了比C语言中更大的灵活性。在Lua中,如果你想调用一个函数f,传入可变数量的参数,很简单,
f(unpack(a))  
unpack返回a中的所有值,并传给f 作为参数,下面示例:
f = string.find  
a = {"hello","ll"}  
print(f(unpack(a)))  --> 3 4  
Lua中的unpack是用C实现的。其实我们也可以用Lua来实现它

function unpack (t,i)  
    i = i or 1  
    if t[i] then  
        return t[i],unpack(t,i + 1)  
    end  
end  
print(string.find("hello","ll")) 
2. 变参
Lua中的一些函数接受可变数量的参数。...表示接受不同数量的实参    {...}表示有变长参数构成的数组

返回所以参数的总和

function add (...)  
    local s = 0  
    for i,v in ipairs{...} do  
        s = s + v  
    end  
    return s  
end  
print(add(3,10,25,12)) --> 54
我们可以将‘...’当作一个表达式,或者一个多返回值的函数(返回当前函数的所有参数)。例如
local a,b = ...  
用可选参数的前两个初始化局部变量a,b的值。再看下面的例子,
function foo(a,b,c)   <==>   function foo(...) local a,c = ...  
function id (...) return ... end  
上面这个函数简单地返回它所有的参数。下面的例子,说明了一个跟踪函数调用的技巧
function foo1 (...)  
    print("calling foo:",...)  
    return foo(...)  
end  

再看一个实用的例子。Lua提供了不同的函数来格式化文本string.formant和写文本io.write,我们可以简单地将二者合二为一。
function fwrite (fmt,...)  
    return io.write(string.format(fmt,...))  
end  
-----注意有一个固定的参数fmt。变参函数可能含有不定数目的固定参数,后面再跟变参。
----Lua会将前面的实参赋值给这些固定参数,剩下的实参才能当作变参看待。下面是几个示例:
--函数                          参数
fwrite()                       -- fmt = nil,no varargs  
fwrite("a")                    -- fmt = "a",no varargs  
fwrite("%d%d",5)           -- fmt = "%d%d",varargs = 4 and 5  
如果想要迭代处理变参,可以用{...}来将所有的变参收集到一个table中。但是有时变参中可能含有非法的nil,我们可以用select函数。select函数一个固定的参数selector,然后跟一系列的变参。调用的时候,如果selector的值为数字n,那么select函数返回变参中的第n个参数,否则selector的值为'#',select函数会返回可变参数的总数目。下面示例:
for i=1,select('#',...) do  
    local arg = select(i,...)     -- get i-th parameter  
    <loop body>  
end  
注意,select("#",...)返回变参的数目,包括nil在内。

3. 带名字的参数
Lua中函数的参数传递是基于位置的,当调用函数的时候,实参根据位置来匹配形参。但是,有的时候,根据名字来匹配更实用。例如,系统函数os.rename,我们会经常忘记新名字和旧名字哪个在前;为了解决这个问题,我们尝试重新定义这个函数。下面这个
-- 无效的演示代码

rename(old="temp.lua",new="temp1.lua")  
上面这个代码是非法的,Lua并不支持这样的语法。但是我们可以修改一点点,来实现相同的效果

function rename (arg)  
    return os.rename(arg.old,arg.new)  
end  
用这种方式来传递参数是很实用的,尤其是,当函数有多个参数,并且其中一些是可有可无时。例如,用GUI库创建一个新的窗口
w = Window{ x=0,y=0,width=300,height=200,title = "Lua",background="blue",border = true  
          }  

Window函数可以检查必须的参数,并且给可选参数赋予认值等。假设_Window函数可以用来创建一个新窗口,但是它必须要全部的参数。那我们就可以重新定义一个Window函数如下:
function Window (options)  
    -- check mandatory options  
    if type(options.title) ~= "string" then  
        error("no title")  
    elseif type(options.width) ~= "number" then  
        error("no width")  
    elseif type(options.height) ~= "number" then  
        error("no height")  
    end  
    -- 其它参数是可选的
    _Window(options.title,options.x or 0,-- default value  
        options.y or 0,-- default value  
        options.width,options.height,options.background or "white",-- default  
        options.border                      -- default is false (nil)  
        )  
end  

相关文章

1.github代码实践源代码是lua脚本语言,下载th之后运行thmai...
此文为搬运帖,原帖地址https://www.cnblogs.com/zwywilliam/...
Rime输入法通过定义lua文件,可以实现获取当前时间日期的功能...
localfunctiongenerate_action(params)localscale_action=cc...
2022年1月11日13:57:45 官方:https://opm.openresty.org/官...
在Lua中的table(表),就像c#中的HashMap(哈希表),key和...