函式
- 函式是對陳述句和運算式進行抽象的主要機制
兩種用法
- 一是可以完成特定的任務,一句函式呼叫被視為一條陳述句
- 二是以只用來計算并回傳特定的結果,視為一句運算式
print("Hello, World")
a = math.sin(3) + math.cos(10)
print(os.date())
- 無論哪種用法都需要將所有引數放到一對圓括號中
- 但如果引數是字面字串或 table 構造式的話,可以放在括號中,也可以不放
- 即使在呼叫函式時沒有引數,也必須有一個 () 空括號,如呼叫 os.date()
print "Hello, World" -- 等價于 print("Hello, World")
print {1, 2, 3} -- 等價于 print({1, 2, 3})
function add(a)
local sum = 0
for i, v in ipairs(a) do
sum = sum + v
end
return sum
end
b = {1, 2, 3}
add(b)
- function 是定義函式的關鍵字
- add 是函式名
- a 是函式的形式引數,是函式定義式引數串列中的引數
- add(b) 呼叫這個函式所傳入的引數稱為實際引數
- 呼叫函式的實際引數的個數可以與函式定義時的形式引數個數不同
- lua 會自動調整實參的數量,以匹配引數表的要求,這和多s重賦值類似
- 若實參少于形參,多余的形參被初始化為 nil
- 若實參多余形參,多余的實參被拋棄
- lua 程式既可以使用 以 lua 撰寫的函式,也可使用 C 語言撰寫的函式
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 被丟棄了
定義一個全域的計數器
function intCount(n)
n = n or 1 -- 賦值一個默認值
count = count + 1
end
面向物件式呼叫函式
- o.foo(o, x)
- o:foo(x) 等價于 o.foo(o, x)
- 冒號運算子使得我們在呼叫 o.foo 時隱含地將 o 作為函式的第一個引數
多重回傳值
- lua 允許函式回傳多個結果
- 如標準庫中的一些預定義函式
-- 用于在字串中定位一個模式的函式 string.find
print(string.find("Hello Lua users", "Lua")) -- 開始的位置 7, 結束的位置 9
- 在 return 后列出需要回傳的所有值即可,用 , 逗號分隔
-- 查找陣列中的最大元素,并回傳這個元素的所在位置
function maximum(a)
local mi = 1 -- 最大值的索引
local max = a[mi] -- 最大值
for i,v in ipairs(a) do
if v > max then
mi = i
max = v
end
end
return max, mi
end
maximum(a) -- 沒有任何反應
print(maximum({3, 4, 23, 5, 7}) -- 23 3
print(maximum({3, 4, 23, 5, 7} .. "a") -- 23a
- 如果將函式呼叫作為單獨的陳述句執行,lua 會丟棄所有的回傳值
- 如果將將函式作為運算式的一部分呼叫,只保留函式的第一個回傳值
- 只有當函式是一系列運算式中的最后一個元素(或只有一個元素的時候),才會獲取所有的回傳值
一系列運算式在 Lua 中的 4 中情況
- 多重賦值
- 函式呼叫時傳入的實參串列
- table 構造式
- return 陳述句
多重賦值
- 在多重賦值中,如果一個函式呼叫是最后(或僅有)的一個運算式,lua 會保留盡可能多的回傳值,用來匹配賦值的變數
- 如果一個函式沒有回傳值或沒有回傳足夠多的回傳值,那么 lua 會用 nil 來補充缺失的值
- 如果一個函式呼叫不是一系列運算式中的最后一個元素,就只能回傳一個值
- 如果一個函式呼叫作為另一個函式呼叫的最后一個(或僅有的)實參的時候,第一個函式的所有回傳值都會作為實參傳遞給另一個函式
function foo0() end
function foo1() return "a" end
function foo2() return "a", "b" end
-- 多重賦值的4種情況
-- 第一種情況
x, y = foo2() -- x = "a" , y = "b"
x = foo2() -- x = "a"
x, y, z = 10, foo2() -- x = 10, y = "a", z = "b"
-- 第二種情況
x, y = foo0() -- x = nil, y = 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
-- 第四種情況
print(foo0()) -- 不會列印任何值
print(foo1()) -- a
print(foo2()) -- a, b
print(foo2(), 20) -- a, 1
print(foo2() .. "x") -- ax
table 構造式
- table 構造式可以完整地接收一個函式呼叫的所有結果,即不會有任何數量方面的調整
- 但這種行為,只有當一個函式呼叫作為最后一個元素時才會發生
- 其他位置上的函式呼叫總是只產生一個結果值
function foo0() end
function foo1() return "a" end
function foo2() return "a", "b" end
t = {foo2()} -- t = {"a", "b"}
t = {foo2(), "x"} -- t = {"a", "x"}
return
- 將函式呼叫放入一對圓括號 () 中,使其只回傳一個結果
- return 陳述句后面的內容不需要 () 圓括號
- 如果強行加上則會使一個多回傳值的函式,強制其只回傳一個 return(f())
function foo0() end
function foo1() return "a" end
function foo2() return "a", "b" end
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)) -- 無回傳值
-- () 包裹
print((foo(1)) -- a
print((foo(2)) -- a
print((foo(0)) -- nil 不太懂為什么
unpack 函式
- 接收一個陣列作為引數
- 并從下標 1 開始回傳該陣列的所有元素
- 這個預定義函式由 C 語言撰寫
print(unpack{10, 20, 30}) -- 10 20 30
a, b = unpack{10, 20, 30} -- a = 10, b = 20
- 用于泛型呼叫
- 泛型呼叫就是可以以任何實參來呼叫任何函式
-- 呼叫任意函式 f, 而所有的引數都在陣列 a 中
-- unpack 將回傳 a 中的所有值,這些值作為 f 的實參
f(unpack(a))
f = string.find
a = {"hello", "ll"}
f(unpack(a)) -- 3 4 等效于 string.find("hello", "ll")
用 lua 遞回實作 unpack
function unpack(t, i)
i = i or 1
if t[i] then
return t[i], unpack(t, i + 1)
end
end
變長引數
- lua 中的函式可以接收不同數量的實參
- 當這個函式被呼叫時,它的所有引數都會被收集到一起
- 這部分收集起來的實參稱為這個函式的「變長引數」
- ... 3個點表示該函式接收不同數量的實參
- 一個函式要訪問它的變長引數時,需要用 ... 三個點,此時 ... 三個點是作為一個運算式使用的
- 運算式 ... 三個點的行為類似一個具有多重回傳值的函式,它回傳的是當前函式的所有變長引數
- 具有變長引數的函式也可以擁有任意數量的固定引數
- 但固定引數一定要在變長引數之前
- 當變長引數中包含 nil ,則需要用 select 訪問變長引數
- 呼叫 select 時,必須傳入一個固定引數 selector(選擇開關) 和一系列變長引數
- 如果 selector 為數字 n ,那么 select 回傳它的第 n 個可變實參
- 否則,select 只能為字串 "#" ,這樣 select 會回傳變長引數的總數,包括 nil
-- 回傳所有引數的和
function add(...)
local s = 0
for i, v in ipairs{...} do -- 運算式{...}表示一個由變長引數構成的陣列
s = s + v
end
return s
end
print(add(3, 4, 5, 100)) -- 115
-- 除錯技巧 ,類似與直接呼叫函式 foo ,但在呼叫 foo 前先呼叫 print 列印其所有的實參
function foo1(...)
print("calling foo:", ...)
return foo(...)
end
-- 獲取函式的實參串列
function foo(a, b, c) end
function foo(...)
local a, b, c = ...
end
-- 格式化文本 string.format ,輸出文本 io.write
-- 固定引數一定要在變長引數之前
function fwrite(fmt, ...)
return io.write(string.format(fmt, ...))
end
fwrite() -- fmt = nil
fwrite("a") -- fmt = a
fwrite("%d%d", 4, 5) -- fmt = "%d%d" , 變長引數 = 4, 5
for i = 1, select('#', ...) do
local arg = select('#', ...)
<回圈體>
end
具名引數
- lua 中的引數傳遞機制是具有 「位置性」的
- 就是說在呼叫一個函式時,實參是通過它在引數表中的位置與形參匹配起來的
- 第一個實參的值與第一個形參相匹配,依此類推
- 定義:通過名稱來指定實參
- 可將所有的實參組織到一個 table 中,并將這個 table 作為唯一的實參傳給函式
- lua 中特殊的函式呼叫語法,當實參只有一個 table 構造式時,函式呼叫中的圓括號是可有可無的
os.rename -- 檔案改名,希望達到的效果 os.rename(old = "temp.lua", new = "temp1.lua")
-- lua 不支持注釋的寫法
rename = {old = "temp.lua", new = "temp1.lua"}
function rename (arg)
return os.rename(arg.old, arg.new)
end
x = Window{x = 0, y = 0, width = 300, height = 200, title = "Lua", background = "blue", border = "true"}
-- Window 函式根據要求檢查必填引數,或為某些函式添加默認值
-- 假設 _Window 是真正用于創建新視窗的函式,要求所有引數以正確次序傳入
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) ~= "height" 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 -- 默認值為 false(nil)
)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/5313.html
標籤:其他
上一篇:lua學習之運算式篇
下一篇:lua學習之復習匯總篇
