【1】函數定義
Lua函數定義格式如下:
1 optional_function_scope function function_name(argument1, argument2, argument3..., argumentn) 2 function_body 3 return result_params_comma_separated 4 end
解析:
optional_function_scope: 該參數是可選的,指定函數是全局函數還是局部函數。
未設置該參數默認為全局函數,如果你需要設置函數為局部函數需要使用關鍵字 local。
function_name: 指定函數名稱。
argument1, argument2, argument3..., argumentn: 函數參數,多個參數以逗號隔開,函數也可以不帶參數。
function_body: 函數體,函數中需要執行的代碼語句塊。
result_params_comma_separated: 函數返回值,Lua語言函數可以返回多個值,每個值以逗號隔開。
【2】Lua函數示例
函數示例
1 --[[ 函數返回兩個值的最大值 --]] 2 local function max(num1, num2) 3 if (num1 > num2) then 4 result = num1; 5 else 6 result = num2; 7 end 8 9 return result; 10 end 11 12 -- 調用函數 13 print("兩值比較最大值為 (10, 4) :: ", max(10, 4)) 14 print("兩值比較最大值為 (5, 6) :: ", max(5, 6)) 15 16 17 --[[ 18 兩值比較最大值為 (10, 4) :: 10 19 兩值比較最大值為 (5, 6) :: 6 20 ]]
【3】Lua函數特色
(1)將函數作為參數傳遞給函數。示例如下:
1 --[[將函數作為參數傳遞給函數]] 2 myprint = function(param) 3 print("這是打印函數 - ##", param, "##") 4 end 5 6 function add(num1, num2, functionPrint) 7 result = num1 + num2 8 -- 調用傳遞的函數參數 9 functionPrint(result) 10 end 11 12 myprint(10) 13 -- myprint 函數作為參數傳遞 14 add(2, 5, myprint) 15 16 --[[ 17 這是打印函數 - ## 10 ## 18 這是打印函數 - ## 7 ## 19 ]]
(2)函數可以返回多個值
例1,代碼如下:
1 --[[例如:string.find 其返回匹配串“開始和結束的下標”(如果不存在匹配串返回nil)]] 2 s, e = string.find("http://www.baidu.com", "baidu") 3 print(s, e) 4 5 --[[執行結果 6 12 16 7 ]] 8 9 s, e = string.find("http://www.google.com", "baidu") 10 print(s, e) 11 12 --[[執行結果 13 nil nil 14 ]]
例2,代碼如下:
1 --[[return后列出要返回值的列表即可返回多值]] 2 function maximum (a) 3 local mi = 1 -- 最大值索引 4 local m = a[mi] -- 最大值 5 for i,val in ipairs(a) do 6 if val > m then 7 mi = i 8 m = val 9 end 10 end 11 return m, mi 12 end 13 14 print(maximum({8, 10, 23, 12, 5})) 15 16 --[[執行結果 17 23 3 18 ]]
例3,特殊函數unpack,它可以接受一個數組作為參數,並從下標1開始返回該數組的所有元素:
1 print(unpack{10, 20, 30}) -- 10 20 30
(3)不定形參函數
3.1 自定義不定形參函數:Lua函數可以接收可變數目的參數
1 function add(...) 2 local s = 0 3 for i, v in ipairs{...} do -- {...} 表示一個由所有變長參數構成的數組 4 s = s + v 5 end 6 return s 7 end 8 9 print(add(3, 4, 5, 6, 7)) -- 25
3.2 將可變參數賦值給一個變量
1 --[[將可變參數賦值給一個變量]] 2 function average(...) 3 result = 0 4 local arg = {...} -- arg 為一個表,局部變量 5 for i,v in ipairs(arg) do 6 result = result + v 7 end 8 print("總共傳入 " .. #arg .. " 個數") 9 return result / #arg 10 end 11 12 print("平均值為", average(10, 5, 3, 4, 5, 6)); 13 14 --[[執行結果 15 總共傳入 6 個數 16 平均值為 5.5 17 ]]
3.3 可以通過select("#", ...來獲取可變參數的數量)
1 --[[可以通過 select("#",...) 來獲取可變參數的數量]] 2 function average(...) 3 result = 0 4 local arg = {...} 5 for i, v in ipairs(arg) do 6 result = result + v 7 end 8 print("總共傳入 " .. select("#", ...) .. " 個數") 9 return result / select("#", ...) 10 end 11 12 print("平均值為", average(10, 5, 3, 4, 5, 6)) 13 14 --[[執行結果 15 總共傳入 6 個數 16 平均值為 5.5 17 ]]
3.4 需要幾個固定參數再加上可變參數時,固定參數必須放在可變參數之前
1 function fwrite(fmt, ...) -- 固定的參數fmt 2 return io.write(string.format(fmt, ...)) 3 end 4 5 fwrite("baidu\n") -- fmt = "baidu", 沒有變長參數。 6 fwrite("%d%d\n", 1, 2) -- fmt = "%d%d", 變長參數為 1 和 2 7 8 --[[執行結果 9 baidu 10 12 11 ]]
3.5 遍歷變長參數時只需要使用{...},然而變長參數可能會包含一些nil,那么就需要用select函數來訪問變長參數。
[1] select('#', ...)返回可變參數的長度
[2] select(n, ...)用於訪問n到select('#', ....)的參數
1 --[[ 2 遍歷變長參數的時候只需要使用{…},然而變長參數可能會包含一些nil,那么就可以用select函數來訪問變長參數了:select('#', …) 或者 select(n, …) 3 select('#', …) 返回可變參數的長度 4 select(n, …) 用於訪問 n 到 select('#',…) 的參數 5 ]] 6 7 do 8 function foo(...) 9 for i = 1, select('#', ...) do --> 獲取參數總數 10 local arg = select(i, ...); --> 讀取參數 11 print("arg", arg); 12 end 13 end 14 15 foo(11, 12, 13, 14); 16 end 17 18 --[[執行結果 19 arg 11 20 arg 12 21 arg 13 22 arg 14 23 ]]
(4)具名實參
具名實參,即具體名稱的實參值。比如,字符串拷貝函數有兩個參數(src, dest),當我們記不清第一個參數是src還是dest時,可以在調用時明確指明具體實參值。
Lua語言中的rename接口,就是個很有代表性的例子。試着新建一個文件temp.lua,然后復制以下代碼段:
1 function rename(arg) 2 return os.rename(arg.old, arg.new) 3 end 4 5 rename({old = "temp.lua", new = "temp1.lua"}) 6 --rename({new = "new1.lua", old = "temp1.lua"})
注意觀察:執行結果,同目錄下會多一個temp1.lua文件
再把第六行的注釋去掉,然后執行結果:同目錄下會多一個new1.lua文件。
(5)待續
【4】深入函數
(1)閉合函數
[1.1] 在Lua中,函數是第一類值
如何理解這個“第一類值”?類比着學習,我們知道C語言的數據類型有整數、浮點數、枚舉、指針、數組、結構、共用體、void等等。
前面我們也學習了《Lua數據類型》包括nil、boolean、number、string、function等等。
即就是,在Lua中,函數可以存儲到變量(無論全局變量還是局部變量)中或table中,可以作為實參傳遞給其他函數,還可以作為其他函數的返回值。
先看最常見的這個求和函數定義:
1 function func(a, b) return a + b end
其等價於
1 func = function(a, b) return a + b end
兩種方式比較:
第一種方式,似乎更符合我們對函數的潛意識(傳統的)視覺印象規則。
第二種方式,更彰顯了Lua中函數作為“第一類值”的體現和范疇。
通過以上兩種方式的對比,我們可以更深入的理解Lua中函數的定義本質:
一個函數定義實質上是一條賦值語句,創建了一種類型為“函數”的值,且將其賦值於變量func。
可以驗證一下類型,如下所示:
1 func = function(a, b) return a + b end 2 print(func) -- function: 02DF8FC8 3 print(type(func)) -- function 4 print(func(10, 20)) -- 30
在Lua中,將表達式“function(x) <body> end”視為一種函數的構造式,就像table的構造式{ }一樣。
將這種函數構造式的結果稱為一個“匿名函數”,雖然一般情況下,會將函數賦予全局變量,即給予其一個名稱。
但是,在某些特殊情況下,仍會需要直接用到匿名函數。
不要問我哪里需要用到,其實你肯定見過,比如sort函數,請看如下示例:
1 students = 2 { 3 {name = "Wang", age = "18"}, 4 {name = "Qin", age = "20" }, 5 {name = "Li", age = "19"}, 6 {name = "Wei", age = "21"}, 7 } 8 9 --[[ before sort ::]] 10 print("before sort ::") 11 for i = 1, #students do 12 print(i, students[i].name, students[i].age) 13 end 14 15 table.sort(students, function(a, b) return (a.name > b.name) end) 16 17 --[[ after sort ::]] 18 print("after sort ::") 19 for k, v in pairs(students) do 20 print(k, v.name, v.age) 21 end 22 23 --[[執行結果 24 before sort :: 25 1 Wang 18 26 2 Qin 20 27 3 Li 19 28 4 Wei 21 29 after sort :: 30 1 Wei 21 31 2 Wang 18 32 3 Qin 20 33 4 Li 19 34 ]]
像sort這樣的函數,接受另一個函數作為實參,稱其是一個“高階函數”,是一種強大的編程機制。
1 names = {"Peter", "Paul", "Mary"} 2 grades = {Mary = 10, Paul = 7, Peter = 8} 3 table.sort(names, function(n1, n2) 4 return grades[n1] > grades[n2] 5 end) 6 7 for k, v in ipairs(names) do 8 print(k, v) 9 end 10 11 --[[ 12 1 Mary 13 2 Peter 14 3 Paul 15 ]] 16 17 names = {"Peter", "Paul", "Mary"} 18 grades = {Mary = 10, Paul = 7, Peter = 8} 19 20 function sortbygrade(names, grades) 21 table.sort(names, function(n1, n2) 22 return grades[n1] > grades[n2] 23 end) 24 return names 25 end 26 27 for k, v in ipairs(sortbygrade(names, grades)) do 28 print(k, v) 29 end 30 31 --[[ 32 1 Mary 33 2 Peter 34 3 Paul 35 ]] 36 37 --[[一般函數]] 38 function increCounter1() 39 local i = 0 40 i = i + 1 41 return i 42 end 43 44 print(increCounter1) -- function: 02A6B8F8 45 print(increCounter1()) -- 1 46 print(increCounter1()) -- 1 47 48 --[[閉合函數]] 49 function increCounter2() 50 local i = 0 51 return function() 52 i = i + 1 53 return i 54 end 55 end 56 57 print(increCounter2) -- function: 02A6B738 58 print(increCounter2()) -- function: 02A6B918 59 60 c1 = increCounter2() 61 print(c1()) -- 1 62 print(c1()) -- 2 63 c2 = increCounter2() 64 print(c2()) -- 1 65 print(c1()) -- 3 66 print(c2()) -- 2 67 68 --[[閉合函數 局部變量]] 69 function increCounter3() 70 return function() 71 local i = 9 72 i = i + 1 73 return i 74 end 75 end 76 77 print(increCounter3) -- function: 02A6B6F8 78 print(increCounter3()) -- function: 02A6B7D8 79 80 c3 = increCounter3() 81 print(c3()) -- 10 82 print(c3()) -- 10 83 c4 = increCounter3() 84 print(c4()) -- 10 85 print(c4()) -- 10 86 print(c4()) -- 10
匿名函數
(2)非全局函數
(3)正確尾調用
【5】總結
Good Good Study, Day Day Up.
順序 選擇 循環 總結