Chapter 5: Functions
print(8*9, 9/8)
a = math.sin(3) + math.cos(10)
print(os.date())
一此特殊情况下,函数可以不带括号
函数只有一个参数,并且这个参数是string,或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({})
object-oriented calls
o:foo(x) 是 o.foo(o,x) 的另一种写法。
参见16 章
函数的实参比形参少用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 is discarded)
函数的这种行为会带来默认参数的效果
以下例子调用incCount() 相当于调用incCount(1)
function incCount (n)
n = n or 1
count = count + n
end
5.1 Multiple Results
函数的多返回值
string.find 函数会返回两个值,第一个是成功匹配的开始索引,第二个是结束索引
s, e = string.find("hello Lua users", "Lua")
print(s, e) --> 7 9
以下函数返回找到的最大值及其在表中的索引
function maximum (a)
local mi = 1 -- index of the maximum value
local m = a[mi] -- maximum value
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})) --> 23 3
用多赋值的形式接收函数的多返回值
function foo0 () end -- returns no results
function foo1 () return "a" end -- returns 1 result
function foo2 () return "a","b" end -- returns 2 results
x,y = foo2() -- x="a", y="b"
x = foo2() -- x="a", "b" is discarded -- 多则丢弃
x,y,z = 10,foo2() -- x=10, y="a", z="b"
x,y = foo0() -- x=nil, y=nil -- 少则补nil
x,y = foo1() -- x="a", y=nil
x,y,z = foo2() -- x="a", y="b", z=nil
x,y = foo2(), 20 -- x="a", y=20 -- 注意
x,y = foo0(), 20, 30 -- x=nil, y=20, 30 is discarded -- 注意
print(foo0()) -->
print(foo1()) --> a
当函数作为另一个函数的最后一个参数时,其全部返回值被当作参数
print(foo2()) --> a b -- print(foo2(), 1) --> a 1
print(1, foo2()) --> 1 a b
print(foo2() .. "x") --> ax (see next)
用函数的返回值构造表
t = {foo0()} -- t = {} (an empty table)
t = {foo1()} -- t = {"a"}
t = {foo2()} -- t = {"a", "b"} -- 函数是表的最后一个参数
t = {foo0(), foo2(), 4} -- t[1] = nil, t[2] = "a", t[3] = 4 -- 函数不是表的最后一个参数
根椐函数实参的不同,让其调用其它不同的函数
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 后面是不需要括号的,return(f(x)) 总是只会返回一个值
特殊的多返回值函数unpack.
unpack 函数以一个数组作为参数(也是表),返回数组的所有元素
print(unpack{10,20,30}) --> 10 20 30
a,b = unpack{10,20,30} -- a=10, b=20, 30 is discarded
unpack 的一个重要应用是泛型调用机制
泛型调用机制允许动态的以任何参数调用任何函数
标准C 中不支持函数的变参,既函数参数的数量是固定的,类型也是固定的。
Lua 中实现变参函数调用
f(unpack(a))
string.find("hello","ll") 的另一种写法:
f = string.find
a = {"hello", "ll"}
f(unpack(a))
内置函数unpack 实际上是C 实现的,下面是lua 实现
unpack 函数的lua 递归实现
function unpack (t, i)
i = i or 1
if t[i] then
return t[i], unpack(t, i + 1)
end
end
5.2 Variable Number of Arguments
参数数量可变的函数 … 函数
以下函数返回其所有参数的和
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
… 的行为像一个多返回值函数
local a, b = ...
function foo (a, b, c) 的另一种写法
function foo (...)
local a, b, c = ...
返回所有传进来的参数的函数
function id (...) return ... end
先打印其所有参数然后在工作的函数
function foo1 (...)
print("calling foo:", ...)
return foo(...)
end
一个更有用的例子
function fwrite (fmt, ...)
return io.write(string.format(fmt, ...))
end
fwrite() fmt = nil, no varargs
fwrite("a") fmt = "a", no varargs
fwrite("%d%d", 4, 5) fmt = "%d%d", varargs = 4 and 5
select 函数
取… 函数的所有参数
for i=1, select('#', ...) do
local arg = select(i, ...) -- get i-th parameter
<loop body>
end
select 函数的第一个参数只能是’#’ 或一个数字n,select('#', ...) 返回… 中所有参数的个数(包含nil),select(n, ...) 则返回… 中第n 个参数
5.3 Named Arguments
以一个表作为参数的函数
function rename (arg)
return os.rename(arg.old, arg.new)
end
name={old="temp.lua", new="temp1.lua"}
rename(name)
某种状况下,这种风格的参数传递特别有用,比如说一个函数有大量参数,而且多数是可选参数。
function Window (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