函數(shù)定義完成后,那么函數(shù)的調(diào)用方式,完成的功能,以及返回值都將固定。此時(shí)就剩下調(diào)用了,對(duì)于調(diào)用函數(shù),只需要關(guān)注參數(shù),并按要求設(shè)置參數(shù),并接收返回值,這樣函數(shù)的整個(gè)流程就完成了。
在Lua中,支持可變參數(shù)定義,即在函數(shù)使用過(guò)程中,傳遞的參數(shù)是可以變化的,可不傳、傳遞一個(gè)、兩個(gè)等等。比如需要計(jì)算一組數(shù)字的累加,那么數(shù)字的個(gè)數(shù)是不固定的。通常會(huì)定義一個(gè)函數(shù),接收一個(gè)table,將不固定的數(shù)字存儲(chǔ)到table中,并作為實(shí)參傳入到函數(shù)中,實(shí)現(xiàn)累加需求:
function adds(numbers)
total = 0
for i, v in pairs(numbers) do
total = total + v
end
return total
end
函數(shù)定義完成后,在使用之前,先將數(shù)字添加到一個(gè)table中,之后完成調(diào)用
nums = { 1, 2, 3 }
t = adds(nums)
print(t)
-->> 6
nums = { 1, 2, 3, 4 }
t = adds(nums)
print(t)
-->> 10
以上按傳統(tǒng)的方式實(shí)現(xiàn)了不固定數(shù)字的累加函數(shù)定義。對(duì)于Lua,可以使用可變參數(shù)的定義方法,完成不固定數(shù)字累加的方法,這種實(shí)現(xiàn)及調(diào)用時(shí)更加方便,畢竟不用在聲明table并組織參數(shù):
function adds(...)
total = 0
for i, v in pairs({ ... }) do
total = total + v
end
return total
end
上面Lua的可變參數(shù)定義,與傳統(tǒng)函數(shù)(參數(shù)為table)定義方式相比,基本上一致,只是將參數(shù)table變更為了...三個(gè)點(diǎn)。雖然函數(shù)定義時(shí),沒(méi)有太大變化,但是在調(diào)用時(shí),將完全不同。
print(adds())
-->> 0
print(adds(1, 2, 3))
-->> 6
print(adds(1, 2, 3, 4))
-->> 10
參數(shù)中的3個(gè)點(diǎn)
...表示該函數(shù)可接受不同數(shù)量的參數(shù)。當(dāng)調(diào)用時(shí),所有的參數(shù)都會(huì)被收集起來(lái),當(dāng)訪問(wèn)可變參數(shù)時(shí),仍然使用3個(gè)點(diǎn)表示,...在使用時(shí),作為一個(gè)表達(dá)式,如上述中的{...},當(dāng)使用{}標(biāo)記可變參數(shù)時(shí),則將其轉(zhuǎn)換為了一個(gè)table。
三個(gè)點(diǎn)...作為表達(dá)式,可以在函數(shù)中直接使用,但在使用時(shí),會(huì)將所有的可變參數(shù)全部返回。
function adds(...)
local a, b = ...
print(a, b)
end
adds(1, 2) -- 讀取可變參數(shù),并賦值給a,b
-->> 1 2
adds(3, 4, 5) -- 讀取可變參數(shù),并賦值給a,b,5將會(huì)被丟棄
-->> 3 4
在定義函數(shù)過(guò)程中,可變參數(shù)也可以和固定位置的參數(shù)混用,但可變參數(shù)必須在最后位置。
function adds(name, ...)
if name ~= nil then
print("name=" .. name)
end
print(...)
end
adds() -- name 和 可變參數(shù)均為nil
adds(1) -- name=1,可變參數(shù)為nil
-->> name=1
adds(1, 2, 3) -- name=1,可變參數(shù)為2,3
-->> name=1
-->> 2 3
在前面,已經(jīng)使用可變參數(shù)...作為表達(dá)式,將其值全部返回,并賦給新的變量;也可以將可變參數(shù)轉(zhuǎn)為數(shù)組{...},并遍歷使用可變參數(shù)。Lua在這兩種讀取可變參數(shù)之外,還提供了select函數(shù),用于訪問(wèn)變長(zhǎng)參數(shù)。該函數(shù)的定義方式為select(index,...),即第一個(gè)位置為固定參數(shù),值包含兩種取值:number和#,如果傳遞數(shù)值,則表示獲取可變參數(shù)指定位置的參數(shù),如果為#,則返回可變參數(shù)的長(zhǎng)度;第二個(gè)參數(shù)為可變參數(shù)本身,仍使用...表示。
function adds(...)
for i, v in pairs({ ... }) do
print(v)
end
end
adds(1, 2, nil, 4)
-->> 1
-->> 2
-->> 4
上述中,無(wú)法使用table獲取到傳遞的nil。為了解決這個(gè)問(wèn)題,可以使用select以便獲取參數(shù)總長(zhǎng)度,以及指定位置的參數(shù)。
function adds(...)
local i = select(2, ...)
print(i)
local i = select(3, ...)
print(i)
local len = select("#", ...) -- 獲取可變參數(shù)的長(zhǎng)度
print(len)
end
adds(1, 2, nil, 4)
-->> 2
-->> nil
-->> 4
可變參數(shù),在使用過(guò)程中,當(dāng)作為表達(dá)式時(shí),完全等價(jià)于原始可變參數(shù),因此可變參數(shù),在一些需要記錄日志時(shí),有著非常良好的應(yīng)用場(chǎng)景,比如類似于Spring切面記錄日志的方式,可以使用Lua的可變參數(shù)來(lái)進(jìn)行模擬
function adds(...)
total = 0
for i, v in pairs({...}) do
total = total + v
end
return total
end
function log(...)
print("執(zhí)行累加操作")
return adds(...)
end
t = log(adds(1, 2, 3, 4))
print(t)
-->> 執(zhí)行累加操作
-->> 10
在Python中,有一種關(guān)鍵詞參數(shù),在調(diào)用時(shí)允許使用關(guān)鍵字對(duì)參數(shù)進(jìn)行限定,并提供必要的檢查手段,對(duì)于程序的擴(kuò)展,有著良好的作用,如下:
def call(name,**kw):
pass
call("ray", language='java', position='beijing')
在Lua中,并不具備命名參數(shù)的功能,但是可以使用table進(jìn)行模擬實(shí)現(xiàn),并且當(dāng)參數(shù)只有一個(gè)時(shí),Lua允許直接跟table,因此從實(shí)用上可以實(shí)現(xiàn)類似的效果。
function worker(employee)
-- 必須具備姓名,開(kāi)發(fā)語(yǔ)言,以及工作年限
if not employee.name or type(employee.name) ~= "string" then
error("員工必須具備姓名")
end
if type(employee.language) ~= "string" then
error("必須具備開(kāi)發(fā)語(yǔ)言")
end
if type(employee.workingYears) ~= "number" then
error("需要工作年限")
end
-- 還有其他屬性,如籍貫省市,月薪等
print(employee.province)
print(employee.city)
print(employee.salary)
end
worker{
name = "ray",
language = "java",
workingYears = 10,
province = "beiijng",
city = "beijing"
}