第六課 深入函式

2021-07-25 06:54:29 字數 3744 閱讀 7544

在lua中,函式是一種「第一類值」(和數字、字串等一樣,具有相同的權利),它們具有特定的詞法域(乙個函式可以巢狀在另乙個函式中,內部函式可以訪問外部函式中的變數)。函式式語言,函式式程式設計。

在lua中有乙個容易混淆的概念是,函式與其他所有值一樣 都是匿名的,即它們都沒有名稱。當討論乙個函式名時(例如print),實際上是在討論乙個持有某函式的變數。這與其他變數持有各種值是一樣的道理。可以以多種方式來操作這些變數。

a =

a.p("hello world")

print =math.sin

a.p(print(1))

sin = a.p

sin(10, 20)

lua中最常見的就是 函式編寫方式,如:

function foo(x) return 2 * x end

只是一種「語法糖」而已,上面這句只是一下** 的一種簡化書寫形式:

foo = function (x) return 2 * x end

因此,乙個函式定義實際上就是一條語句(更準確地說就是一條賦值語句),這條語句建立了一種型別為「函式」的值。並將這個值賦予乙個變數。可以將表示式「function(x) end」視為一種函式的構造式,就像table的構造式{}一樣。將這種函式構造式的結果稱為乙個「匿名函式」。雖然一般情況下,會將函式賦予全域性變數,即給予其乙個名稱。但在某些特殊情況中,仍會需要用到匿名函式。

table庫中的函式table.sort,對table中的元素進行排序。sort函式沒有提供排序準則(按公升序或降序、按數字順序等),而是提供了乙個所謂」次序函式「。這個函式接受兩個元素,並返回在有序情況下第乙個元素是否應該排在第二個元素前面。

network =

} 如果以name欄位、按照反向的字元順序來對這個table排序的話,只需要這麼寫:

table.sort(network, function (a, b) return (a.name > b.name) end)

像sort這樣的函式,接受另乙個函式作為其實參的,稱其為乙個「高階函式」。

閉合函式closure

若將乙個函式寫在另乙個函式之內,那麼位於內部的函式便可以訪問外部函式中的區域性變數,這項特徵稱之為「詞法域」。

function sortbygrade(names, grades)

table.sort(names, function(n1, n2) return grades[n1] > grades[n2] end)

end內部的匿名函式可以訪問外部函式sortbygrade的引數grades,即sortbygrade的區域性變數。在這個匿名函式內部,grades既不是全域性變數,也不是區域性變數,將其稱為乙個「非區域性的變數」。

從技術上講,lua中只有closure,而不存在「函式」,因為函式本身就是一種特殊的closure。

可以使用這樣的技術來建立乙個安全的執行環境,即所謂的「沙盒( sandbox)」 do

local oldopen = io.open

local access_ok = function(filename ,mode)

《檢查訪問許可權》

endio.open = function(filename, mode)

if access_ok(filename, mode) then

return oldopen(filename, mode)

else

return nil, "access denied"

endend

end經過重新定義後,乙個程式就只能通過新的受限版本來呼叫原來的那個未受限制的open函式了。

非全域性的函式

函式不僅可以儲存在全域性變數中,還可以儲存在table的字段中和區域性變數中。

將函式儲存在table欄位中,大部分lua庫都使用了這種機制。(io.read,math.sin)

lib = {}

lib.foo = function (x, y) return x + y end

lib.goo = function (x, y) return x - y end 或者

lib = 或者

lib = {}

function lib.foo(x, y) return x + y end

function lib.goo(x, y) return x - y end

區域性函式

local f = function (引數)

《函式體》

end或者(區域性函式定義語法糖)

local function f(引數)

《函式體》

end在定義遞迴的區域性函式時,還有乙個特別之處需要注意。

local fact = function (n)

if n == 0 then return 1

else return n * fact(n -1) --錯誤,這時區域性的fact還未定義完,這裡

的fact只能是表示全域性函式fact

endend

修改為:

local fact

fact = function (n)

if n == 0 then return 1

else return n * fact(n -1)

endend

當lua展開區域性函式定義的語法糖時,並不是使用基本函式定義語法。而是對於區域性函式定義:

local function foo (《引數》) 《函式體》 end

lua將其展開為:

local foo

foo = function (《引數》) 《函式體》 end

因此,使用這種語法來定義遞迴函式不會產生錯誤:

local function fact(n)

if n == 0 then return 1

else return n * fact(n - 1)

endend

這個技巧對於間接遞迴的函式而言是無效的。在間接遞迴的情況中,必須使用乙個明確的前向宣告。

local f, g

function g()

f()end

function f()

g()end

別把第二個函式定義為「local function f」如果那樣的話,lua會建立乙個全新的區域性變數f,而將原來宣告的f(函式g中所引用的那個)置於未定義的狀態。

正確的尾呼叫

lua支援「尾呼叫消除」(類似goto的呼叫)。當乙個函式呼叫是另乙個函式的最後乙個動作時,該呼叫才算是一條「尾呼叫」。

function f(x) return g(x) end --g(x)的呼叫就是一條尾呼叫

f呼叫完g之後就再無其他事情可做了。因此,程式就不需要返回那個「尾呼叫」 所在的函式了。在「尾呼叫」之後,程式也不需要儲存任何關於該函式的棧資訊了。有一些語言實現可以得益於這個特點,使得在進行「尾呼叫」時不耗費任何棧空間。將這種實現稱之為支援「尾呼叫消除」。

「尾呼叫」不會耗費棧空間,所以乙個程式可以擁有無數巢狀的「尾呼叫」。

在呼叫一下函式時,傳入任何數字作為引數都不會引起棧溢位。

function foo (n)

if n > 0 then return foo(n - 1) end

end在lua中,只有「return ()」這樣的呼叫形式才算是一條「尾呼叫」。lua在呼叫前對以及其引數求值,所以它們可以是任何複雜的表示式。如:

return x[i].foo(x[j] + a * b, i + j)

尾呼叫類似goto,因此在lua中「尾呼叫」的一大應用就是編寫「狀態機」。這種程式通常以乙個函式來表示乙個狀態,改變狀態就是goto到另乙個特定的函式。

第六課 字型

a.字型系列 font family times new roman times,serif b.字型樣式 font style normal 正常 正常顯示文字 font style italic 斜體 以斜體字顯示的文字 font style oblique 傾斜的文字 文字向一邊傾斜 和斜體非...

第六課 列表

序列是python中最基本的 種資料結構。序列 於儲存 組有序的資料,所有的資料在序列當中都有 個唯 的位置 索引 並且序列中的資料會按照新增的順序來分配索引。資料結構指計算機中資料儲存的 式。python 基礎教程 第二版 對序列的定義為 資料結構。資料結構是通過某種方式 例如對元素進行編號 組織...

第六課 Python函式 三

函式的巢狀是指在函式內再定義乙個函式,舉個例子 def outter name jack 被下層函式使用 age 20 被下層函式使用 address yn 被下層函式做返回值 height 178 沒有被下層函式使用 definner new name name 0 3 new age age 1...