一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

腳本之家,腳本語(yǔ)言編程技術(shù)及教程分享平臺(tái)!
分類導(dǎo)航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務(wù)器之家 - 腳本之家 - Lua - Lua中函數(shù)與面向?qū)ο缶幊痰幕A(chǔ)知識(shí)整理

Lua中函數(shù)與面向?qū)ο缶幊痰幕A(chǔ)知識(shí)整理

2020-05-07 11:26林壽山 Lua

函數(shù)在面對(duì)對(duì)象的編程中又被叫做方法,會(huì)受到作用域的制約,Lua中具有類等面向?qū)ο蟮奶匦?接下來(lái)我們就來(lái)看一下Lua中函數(shù)與面向?qū)ο缶幊痰幕A(chǔ)知識(shí)整理

函數(shù)
1. 基礎(chǔ)知識(shí)

調(diào)用函數(shù)都需要寫圓括號(hào),即使沒(méi)有參數(shù),但有一種特殊例外:函數(shù)若只有一個(gè)參數(shù)且參數(shù)是字面字符串或table構(gòu)造式,則圓括號(hào)可有可無(wú),如dofile 'a.lua',f{x=10, y=20}。

Lua面向?qū)ο?/a>式的調(diào)用提供冒號(hào)操作符的特殊語(yǔ)法,如o.foo(o, x)等價(jià)于o:foo(x)。和Javascript類似,調(diào)用函數(shù)時(shí)提供的實(shí)參數(shù)量可以與形參數(shù)量不同,若實(shí)參多了則舍棄,不足則多余的形參初始化為nil。

1.1 多重返回值

Lua允許函數(shù)返回多個(gè)結(jié)果,函數(shù)返回如return max, index,接收如s, e = string.find("hello Lua world", "Lua")。如果一個(gè)函數(shù)調(diào)用不是一系列表達(dá)式的最后一個(gè)元素,則只產(chǎn)生一個(gè)值:

1
2
3
function foo() return "a", "b" end
x, y = foo(), 20  -- x="a", y=20(foo的第二個(gè)返回值被丟棄)
print(foo() .. "x")  -- 輸出ax,這是因?yàn)楫?dāng)函數(shù)出現(xiàn)在一個(gè)表達(dá)式中時(shí),Lua會(huì)將其返回值數(shù)量調(diào)整為1

另外,只有當(dāng)一個(gè)函數(shù)調(diào)用作為最后一個(gè)元素時(shí),返回值才不會(huì)被調(diào)整,在其他位置都會(huì)被調(diào)整為1個(gè),如t = {foo2()}則t={“a”, “b”},t = {foo2(), 4}則t={“a”, 4}。

特殊函數(shù)unpack接受一個(gè)數(shù)組作為參數(shù),并從下標(biāo)1開(kāi)始返回該數(shù)組的所有元素,如a, b = unpack({10, 20, 30}),則30被丟棄。unpack的一項(xiàng)重要用途體現(xiàn)在“泛型調(diào)用”機(jī)制中。

1.2 變長(zhǎng)參數(shù)

函數(shù)參數(shù)表中3個(gè)點(diǎn)(…)表示該函數(shù)可接受不同數(shù)量的實(shí)參。在Lua 5.0中,沒(méi)有提供“…”表達(dá)式,如果要遍歷變長(zhǎng)參數(shù),可以訪問(wèn)函數(shù)內(nèi)隱含的局部變量arg。如果還有固定參數(shù),則必須放在變長(zhǎng)參數(shù)之前。

2. 高級(jí)主題
2.1 closure閉合函數(shù)

和Javascript的閉包基本是一個(gè)東西,此處不再贅述。從技術(shù)上說(shuō),Lua中只有closure,而不存在“函數(shù)”,因?yàn)楹瘮?shù)本身就是一種特殊的closure。closure的應(yīng)用很廣泛,如用于高階函數(shù)的參數(shù)、為GUI工具包創(chuàng)建回調(diào)、重定義函數(shù)并在新實(shí)現(xiàn)中調(diào)用舊實(shí)現(xiàn)、創(chuàng)建“沙盒”安全運(yùn)行環(huán)境等等。

2.2 非全局的函數(shù)

大部分Lua庫(kù)都采用了將函數(shù)存儲(chǔ)在table中的機(jī)制(如io.read,math.sin),例如下面采用了三種方式來(lái)定義table的成員函數(shù):

?
1
2
3
4
5
MathLib = {
  plus = function(x, y) return x + y end
}
MathLib.minus = function(x, y) return x - y end
function MathLib.multiply(x, y) return x * y end

局部函數(shù)的定義:

?
1
2
local f = function(<參數(shù)>) <函數(shù)體> end
local function f(<參數(shù)>) <函數(shù)體> end -- Lua提供的語(yǔ)法糖

**注意如果定義遞歸函數(shù),不能使用上面第一種定義方式(因?yàn)樵诤瘮?shù)體調(diào)用f時(shí),f尚未定義完畢),使用第二種“語(yǔ)法糖”則沒(méi)問(wèn)題;或者使用“前向聲明”,先local f再f = function ...這樣定義。

2.3 正確的尾調(diào)用

當(dāng)一個(gè)函數(shù)調(diào)用時(shí)另一個(gè)函數(shù)的最后一個(gè)動(dòng)作時(shí),該調(diào)用算是一條“尾調(diào)用”,例如function f(x) return g(x) end。由于在尾調(diào)用后程序不要保存任何關(guān)于該函數(shù)的棧信息,所以遞歸調(diào)用不會(huì)耗費(fèi)棧空間,可以遞歸調(diào)用無(wú)數(shù)次。有一些看似是“尾調(diào)用”的代碼,其實(shí)都違背了這條準(zhǔn)則:

?
1
2
3
function f(x) g(x) end  -- 調(diào)用g后,f沒(méi)有立即返回,還需要丟棄g返回的臨時(shí)結(jié)果
function f(x) return g(x) + 1  -- 還要做一次加法
function f(x) return x or g(x)  -- 必須調(diào)整為一個(gè)返回值

所以,只有形如return <func>(<args>)這樣的調(diào)用形式才算是尾調(diào)用。

面向?qū)ο缶幊?/strong>
Lua中的table就是一種對(duì)象,因?yàn)樗蛯?duì)象一樣可以擁有狀態(tài),也擁有一個(gè)獨(dú)立于其值的標(biāo)識(shí)(一個(gè)self),也和對(duì)象一樣具有獨(dú)立于創(chuàng)建者的生命周期。但是Lua中沒(méi)有類的概念,只能用元表來(lái)實(shí)現(xiàn)原型,用原型來(lái)模擬類和繼承等面向?qū)ο筇匦浴1疚膶⒔榻BLua關(guān)于面向?qū)ο缶幊痰膬?nèi)容。

1 self與冒號(hào)語(yǔ)法

使用self參數(shù)是所有面向?qū)ο笳Z(yǔ)言的一個(gè)核心,Lua只需使用冒號(hào)語(yǔ)法,就能隱藏該參數(shù),例如下面兩段代碼是等價(jià)的。

?
1
2
3
4
5
6
7
8
9
10
11
12
Account = {balance=0}
funtion Account.withdraw(self, v)
  self.balance = self.balance - v
end
a1 = Account; Account = nil
a1.withdraw(a1, 100.0) -- 注意這是可以運(yùn)行的
 
function Account:withdraw(v)
  self.balance = self.balance - v
end
a2 = Account
a2:withdraw(100.0) -- 省略了a2參數(shù)傳入

2 類的編寫

在一些基于原型的語(yǔ)言中,對(duì)象是沒(méi)有類型的,但每個(gè)對(duì)象都有一個(gè)原型。原型是一種常規(guī)的對(duì)象,當(dāng)其他對(duì)象遇到一個(gè)未知操作時(shí),原型會(huì)先查找它。在這種語(yǔ)言中要表示一個(gè)類,只需創(chuàng)建一個(gè)專用做其他對(duì)象的原型。Lua中實(shí)現(xiàn)原型很簡(jiǎn)單,只需用元表的__index來(lái)實(shí)現(xiàn)繼承。

(當(dāng)訪問(wèn)一個(gè)table中不存在的字段key時(shí),一般得到結(jié)果為nil。事實(shí)上,訪問(wèn)會(huì)促使解釋器去查找一個(gè)叫__index的元方法,如果沒(méi)有這個(gè)元方法,則訪問(wèn)結(jié)果如前述的nil,否則由這個(gè)元方法來(lái)提供結(jié)果。元方法除了是一個(gè)函數(shù),還可以是一個(gè)table,如果是table則直接返回該table中key對(duì)應(yīng)的內(nèi)容。)

如果有兩個(gè)對(duì)象a和b,要讓b作為a的一個(gè)原型,只需setmetatable(a, {__index=b})。a就會(huì)在b中查找它沒(méi)有的操作。

?
1
2
3
4
5
6
function Account:new(o)
  o = o or {} -- 如果用戶沒(méi)有提供table,則創(chuàng)建一個(gè)
  setmetatable(o, self)
  self.__index = self
  return o
end

當(dāng)調(diào)用a = Account:new{balance = 0}時(shí),a會(huì)將Account(函數(shù)中的self)作為其元表。當(dāng)調(diào)用a:withdraw(100.0)時(shí),Lua無(wú)法在table a中找到條目withdraw,則進(jìn)一步搜索元表的__index條目,即getmetatable(a).__index.withdraw(a, 100.0)。由于new方法中做了self.__index = self,所以上面的表達(dá)式又等價(jià)于Account.withdraw(a, 100.0),這樣就傳入了a作為self參數(shù),又調(diào)用了Account類的withdraw函數(shù)。這種創(chuàng)建對(duì)象的方式不僅可以作用于方法,還可以作用于所有其他新對(duì)象中沒(méi)有的字段。

3 繼承

現(xiàn)在要從Account類派生出一個(gè)子類SpecialAccount(以使客戶能夠透支),只需:

?
1
2
SpecialAccount = Account:new()
s = SpecialAccount:new{limit=1000.00}

SpecialAccount從Account繼承了new,當(dāng)執(zhí)行SpecialAccount:new時(shí),其self參數(shù)為SpecialAccount,因此s的元表為SpecialAccount。當(dāng)調(diào)用s不存在的字段時(shí),會(huì)向上查找,也可以編寫新的重名方法覆蓋父類方法。

4 多重繼承

上面介紹中為_(kāi)_index元方法賦值一個(gè)table實(shí)現(xiàn)了單繼承,如果要實(shí)現(xiàn)多重繼承,可以讓__index字段成為一個(gè)函數(shù),在該函數(shù)中搜索多個(gè)基類的方法字段。由于這種搜索具有一定復(fù)雜性,多重繼承的性能不如單一繼承。還有一種改進(jìn)性能的簡(jiǎn)單做法是將繼承的方法復(fù)制到子類中,但這種做法的缺點(diǎn)是當(dāng)系統(tǒng)運(yùn)行后就較難修改方法的定義,因?yàn)檫@些修改不會(huì)沿著繼承體系向下傳播。

5 私密性

Lua在設(shè)計(jì)對(duì)象時(shí),沒(méi)有提供私密性機(jī)制(private),但其各種元機(jī)制使得程序員可以模擬對(duì)象的訪問(wèn)控制。這種實(shí)現(xiàn)不常用,因此只做基本的了解:通過(guò)兩個(gè)table來(lái)表示一個(gè)對(duì)象,一個(gè)用來(lái)保存對(duì)象的狀態(tài),一個(gè)用于對(duì)象的操作(即接口)。

?
1
2
3
4
5
6
7
8
9
function newAccount(initialBalance)
  local self = {balance = initialBalance}
  local withdraw = function(v)
    self.balance = self.balance -v
  end
  return {
    withdraw = withdraw
  }
end

通過(guò)閉包的方式,將具有私密性的字段(如balance)保存在self table中,并只公開(kāi)了withdraw接口,這樣就能實(shí)現(xiàn)私密性機(jī)制。

延伸 · 閱讀

精彩推薦
  • LuaLua中的元方法__newindex詳解

    Lua中的元方法__newindex詳解

    這篇文章主要介紹了Lua中的元方法__newindex詳解,本文講解了查詢與更新、監(jiān)控賦值、通過(guò)table給另一個(gè)table賦值等內(nèi)容,需要的朋友可以參考下 ...

    笨木頭8872020-04-09
  • LuaLua和C語(yǔ)言的交互詳解

    Lua和C語(yǔ)言的交互詳解

    這篇文章主要介紹了Lua和C語(yǔ)言的交互詳解,Lua和C語(yǔ)言通過(guò)棧完成交互,本文結(jié)合代碼實(shí)例詳細(xì)講解了交互的方法,需要的朋友可以參考下 ...

    果凍想3702020-04-14
  • LuaLua教程(二):基礎(chǔ)知識(shí)、類型與值介紹

    Lua教程(二):基礎(chǔ)知識(shí)、類型與值介紹

    這篇文章主要介紹了Lua教程(二):基礎(chǔ)知識(shí)、類型與值介紹,本文講解了Hello World程序、代碼規(guī)范、全局變量、類型與值等內(nèi)容,需要的朋友可以參考下 ...

    腳本之家5922020-04-28
  • LuaLua實(shí)現(xiàn)__add方法重載示例

    Lua實(shí)現(xiàn)__add方法重載示例

    這篇文章主要介紹了Lua實(shí)現(xiàn)__add方法重載示例,本文直接給出實(shí)現(xiàn)代碼,需要的朋友可以參考下 ...

    腳本之家7452020-04-24
  • Lua深入探究Lua中的解析表達(dá)式

    深入探究Lua中的解析表達(dá)式

    這篇文章主要介紹了深入探究Lua中的解析表達(dá)式,對(duì)于其語(yǔ)法部分的說(shuō)明和示例都超詳細(xì),極力推薦此文!需要的朋友可以參考下 ...

    腳本之家3542020-05-05
  • LuaLua簡(jiǎn)介、編譯安裝教程及變量等語(yǔ)法介紹

    Lua簡(jiǎn)介、編譯安裝教程及變量等語(yǔ)法介紹

    這篇文章主要介紹了Lua簡(jiǎn)介、編譯安裝教程及變量等語(yǔ)法介紹,本文同時(shí)講解了lua注釋語(yǔ)法、Lua命令行方式等內(nèi)容,需要的朋友可以參考下 ...

    junjie3632020-04-14
  • LuaLua中table庫(kù)函數(shù)方法介紹

    Lua中table庫(kù)函數(shù)方法介紹

    這篇文章主要介紹了Lua中table庫(kù)函數(shù)方法介紹,本文講解了concat、insert、maxn、remove、sort、foreachi等方法,需要的朋友可以參考下 ...

    腳本之家2502020-04-17
  • LuaLua中計(jì)算、執(zhí)行字符串中Lua代碼的方法

    Lua中計(jì)算、執(zhí)行字符串中Lua代碼的方法

    這篇文章主要介紹了Lua中計(jì)算、執(zhí)行字符串中Lua代碼的方法,類似JavaScript中eval函數(shù)的功能,在Lua中也可以實(shí)現(xiàn),需要的朋友可以參考下 ...

    腳本之家6322020-04-30
主站蜘蛛池模板: 午夜十八岁禁 | 亚洲精品www久久久久久久软件 | 男女做受快插大片 | 动漫美女被吸乳羞羞小说 | 我和老丈洗澡同性 | 女性性色生活片免费观看 | 波多野结衣家庭教师 | a一级毛片录像带 录像片 | 国产日产精品久久久久快鸭 | 国产麻豆91网在线看 | 丁香成人社 | 成人依依网| 美女扒开两腿露出尿口的视频 | 插得好舒服 | 欧美成人在线影院 | 99精品视频在线观看免费播放 | 麻豆在线md0087免费 | 青春草视频免费观看 | 免费国产午夜高清在线视频 | 欧美极品摘花过程 | 亚洲精品www久久久久久久软件 | 女人张开腿让男人做爽爽 | adult video在线观看 | 亚洲国产精品无码中文字满 | 毛片亚洲毛片亚洲毛片 | 女人又色又爽又黄 | 星星动漫在线观看无删减 | 欧美不卡一区二区三区 | 日本色播| 丁香婷婷在线视频 | 国产精品久久国产三级国电话系列 | 日本私人影院 | 婷婷色伊人 | 美女艹b| 99久久国产亚洲综合精品 | 四虎成人免费视频 | 国产精品午夜剧场 | 亚欧视频在线观看 | 欧美ⅹxxxhd3d | 俄罗斯三级在线观看级 | 国产成人亚洲综合91精品555 |