第六章 深入理解函數 Lua程序設計筆記
阿新 • • 發佈:2017-11-26
tail pri 實例 lar 就是 else tab got ati
--第六章 深入理解函數
Lua中函數是“第一類值”,與其他傳統類型有相同的權利:
可以儲存到變量或table中,可以作為函數實參傳遞,還可以作為函數的返回值。
函數的標準定義:
foo = function(x) return x*2 end
一個函數定義實際上就是一條賦值語句,這條語句創建了一種類型為“函數”的值,並將這個值賦予一個變量。
--6.1closure(閉合函數)
function newCounter() local i = 0 return function() i = i + 1 return i end end
非局部的變量(non-local variable):
是外部函數的局部變量,在內部的匿名函數中,既不是局部也不是全局變量。如上面的i。
一個closure就是一個函數加上該函數所需訪問的所有“非局部的變量”。
c1和c2是同一個函數創建的兩個不同的closure,它們各自擁有局部變量i的獨立實例。
c1 = newCounter() print(c1()) -->1 print(c1()) -->2 c2 = newCounter() print(c2()) -->1 print(c1()) -->3 print(c2()) -->2
--6.2非全局函數
一個錯誤的示例:
local fact = function(n) if n == 0 then return 1 else return n * fact(n-1) end end
當編譯到函數體中調用fact(n-1)時,由於局部fact尚未定義完畢,因此這個語句其實調用了一個全局的fact。
正確的寫法:
local fact fact = function(n) if n == 0 then return 1 else return n * fact(n-1) end end
現在函數中的fact調用就表示局部變量。
使用語法糖
local function foo() <body> end
Lua將其展開為:
local foo foo = function() <body> end
因此使用語法糖可以直接定義遞歸:
local function fact(n) if n == 0 then return1 else return n*fact(n-1) end end
但是對於間接遞歸,必須使用明確的前向聲明(forward declaration)
local f,g function g() ... f() ... end function f() ... g() ... end
--6.3正確的尾調用(tail call)
當一個函數調用的是另一個函數的最後動作是,才是一條尾調用:
function f(x) return g(x) end
不是尾調用的示例:
function f(x) g(x) end --調用完g後,f並不能立即返回,而還需要丟棄g返回的臨時結果 return g(x) + 1 --還要做一個加法 return x or g(x) --還要調整為一個返回值 return (g(x)) --還要調整為一個返回值
一個尾調用就好比一個goto語句,迷宮遊戲的案例:
function room1() local move = io.read() if move == "south" then return room3() elseif move == "east" then return room2() else print("invalid move") return room1() end end function room2() local move = io.read() if move == "south" then return room4() elseif move == "west" then return room1() else print("invalid move") return room2() end end function room3() local move = io.read() if move == "north" then return room1() elseif move == "east" then return room4() else print("invalid move") return room3() end end function room4() print("congratulations!") end
通過調用room1()進入遊戲
第六章 深入理解函數 Lua程序設計筆記