函数
Lua为面向对象式的调用也提供了一种特殊的语法——冒号操作符。表达式o.foo(o,x)的另一种写法是o:foo(x),
冒号操作符使调用o.foo时将o隐含地作为函数的第一歌参数。
一个Lua程序既可以使用以Lua编写的函数,又可以调用以C语言编写的函数。
function incCount(n)
n=n or 1
count = count+n
end
多重返回值
Lua具有一项非常与众不同的特征,允许函数返回多个结果。Lua的几个预定义函数就是返回多个值的。
Lua的几个预定义函数就是返回多个值的。例如,用于在字符串中定位一个模式(pattern)的函数string.find。
该函数若在字符串中找到了指定的模式,将返回匹配的起始字符和结尾字符的索引。在此就需要使用多重赋值
语句来接收函数的返回值。
s,e=string.find("hello Lua users", "Lua")
print(s,e)-->7 9
以Lua编写的函数同样可以返回多个结果,只需要在return关键字后列出所有的返回值即可。例如,需要写一个
函数用于查找数组中的最大元素,并返回该元素的位置:
function maximum(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(maximum({8,10,23,12,5}))
Lua会调整一个函数的返回值数量以适应不同的调用情况。
变长参数
Lua中的函数还可以接受不同数量的实参。例如,在调用print时可以传入一个、二个或多个实参。虽然print
是用C语言编写的,但也可以用Lua编写这种能接受不同数量实参的函数。
下面是一个简单例子,这个函数返回所有参数的总和:
function add(...)
local s=0
for i,v in ipairs{...} do
s=s+v
end
return s
end
print(add(3,4,10,25,12))-->54
参数表中的3个点(...)表示该函数可以接受不同数量的实参。当这个函数被调用时,它的所有参数都会被
收集到一起。这部分收集起来的实参称为这个函数的“变长参数”。一个函数要访问它的变长参数时,仍需
用到3个点(...)。但不同的是,此时这3个点是作为一个表达式来使用的。在上例中,表达式{...}表示一 个由所有变长参数构成的数组。而函数add遍历了该数组,并累加了每个元素。 表达式“...”的行为类似于一个具有多重返回值的函数,它返回的是当前函数的所有变长参数。例如: local a,b=...用第一个和第二个变长参数来初始化这两个局部变量。实际上,还可以通过变长参数 来模拟Lua中普通的参数传递机制,例如: function foo(a,b,c) 可以转换为: function foo(...) local a,b,c=... end 对于哪些喜爱Perl参数传递机制的人来说,可能会更倾向于第二种形式。 若有这样一个函数: function id(...) return ... end 它只是简单地返回调用它时传入的所有实参,这是一个“多值恒定式”函数。下这个函数的行为非常类似于 直接调用函数foo,但在调用foo前先调用print打印出其所有的实参: function foo1(...) print("calling foo:",...) return foo(...) end 这种技巧对于跟踪某个特定的函数调用很有帮助。 Lua提供了专门用于格式化文本(string.format)和输出文本(io.write)的函数。很自然地会想到将函数 合二为一: function fwrite(fmt,...) return io.write(string.format(fmt,...)) end 注意在3歌点前有一个固定参数fmt。具有变长参数的函数同样也可以拥有任意数量的固定参数,但固定参数必须放在变长参数之前。Lua会将前面的实参赋予固定参数,而将余下的实参视为变长参数。 通常一个函数在遍历其变长参数时只需要使用表达式{...},这就像访问一个table一样,访问所有变长参数。然而在 某些特殊的情况下,变长参数中可能包含一些故意传入的nil,那么此时就需要用函数select来访问变长参数了。调用select时,必须传入一个固定实参selector(选择开关)和一些列变长参数。如果selector位数字n,那么select返回它的第n个可变实参;否则,selector可能为字符串“#”,这样select会返回变长参数的总数。下面的循环演示了如何使用select来遍历一个函数的所有变长参数: for i=1,select('#',...) do local arg=select(i,...) end select("#",...)会返回所有变长参数的总数,其中包括nil。
具名实参 Lua中的参数传递机制是具有“位置性”的,也就是说在调用一个函数时,实参是通过它在参数表中的位置与形参匹配 起来的。第一个实参的值与第一个形参相匹配,依次类推。但有时通过名称来指定实参也是很有用的。 os.rename,这个函数用于文件改名。通常会忘记第一个参数是表示新文件名还是旧文件名。因此,会希望这个函数能够接受两个具有名称的实参。 rename{old="temp.lua",new="temp1.lua"} 另一方面,将rename改为只接受一个参数,并从这个参数中获取实际的参数: 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) if type(options.titile) ~= "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 options.y or 0 options.width,options.height, options.background or "white", options.border) end
|
请发表评论