**lua的物件導向實現很有趣,lua的基本資料型別有8個 nil ,number ,string , boolean , function , table , userdata , thread 。其中的table就是實現物件導向的重中之重 ,lua對table的一些機制設計十分巧妙,只需要熟悉這些機制 ,用簡潔的**就能實現物件導向,不得不讓我佩服lua語言設計者的厲害!
每個table都可以有自己的原表,但table建立新的表時並不會建立原表,即其原表為nil
t=
print
(getmetatable
(t))
--> nil
使用元方法getmetatable,獲取其原表,列印輸出,結果為nil。可以使用setmetatable的方法給表設定原表
t=
metatable=
setmetatable(t,metatable)
print(getmetatable(t))--> table:0x005a11f2
看到輸出的結果為原表的位址。
元方法是個非常牛x的機制,我們知道c++ ,c#裡有個概念叫過載預算符,就是可以自定義加減乘除的運算子方法,lua也提供了這樣的功能,不過lua是靠原表元方法__add(+),__sub(-),__mul(*),__div(/)來實現的,比如我們可以通過這些方法實現兩個table進行相加,即求合集的功能
set=
local metatable=
function set.new(l)
local set=
setmetatable(set,metatable)
for _,v in ipairs(l)
do set[v]
=true
endreturn
setend
function set.union(a,b)
local res=set.new(
)for k in pairs(a)
do res[k]
=true end
for k in pairs(b)
do res[k]
=true end
return res
ends1=set.new
s2=set.new
print(getmetatable(s1))
print(getmetatable(s2))
metatable.__add=set.union
s3=s1+s2
forvin pairs(s3)
do print(v)
endprint(s3)
輸出結果如下:
table: 0x006a19f0
table: 0x006a19f012
3457
89table: 0x006a1ce8
lua也提供了一些關係類的元方法,比如:__eq,__lt,__le,下面來介紹下最重要的乙個元方法,__index
lua模擬物件導向,少不了它。
如何實現類?
首先要建立這樣的概念,就是每個物件要有乙個原型(prototype),當物件的例項遇到乙個未知操作時,原型先會去查詢這個操作,找到了就回去執行它。如果有兩個物件a和b,把b作為a的原型,我們輸入如下語句
```bash
setmetatable(a,)
那麼當a遇到位置操作時就會在b中查詢有沒有這樣的操作。
熟悉物件導向我們知道,乙個類包含建構函式,字段,屬性,方法,那麼我們用下面的**來模擬乙個類
account=
function account:new(o)
o=o or
setmetatable(o,self)
self.__index=self
return o
endfunction account.withdraw(self,v)
self.balance=self.balance-v
enda=account:new
;a.withdraw(a,1)
print(a.balance)
這段**裡我們用到了__index,它的意思就是設定表的原型索引,這裡我們把account這個table的原表設定為自己,原型索引也設定為自己這個table,分析下**的工作流程,當我們建立了account 的例項a,並呼叫withdraw這個未知操作時,a會先查詢自己的原表,發現原表就是account,那麼去執行withdraw方法時,發現自身並沒有withdraw這個方法,就會去查詢原表裡的元方法__index,然後發現account.__index也是account,那麼就會去呼叫account的withdraw方法。這樣是不是就實現了類的繼承,是不是十分巧妙?如果要實現過載也很簡單,那就在a裡再寫個withdraw方法。
那麼如果要實現多重繼承,例如類似c#裡的介面,怎麼做呢?__上例裡__index只是給了父類自身,要實現多重繼承,我們可以將所有繼承的父類存在一張table裡並且給這個物件設定乙個特殊的原表,__index元方法給乙個函式,讓其可以在父類裡搜尋遍歷所搜父類同名方法,那麼不就實現多重繼承了嗎?上**:
local function search(k,plist)
for i=1,#plist do
local v=plist[i]
[k]if
vthen
return
v end
endend
function createclass(
...)
local c=
local parents=
setmetatable(c,
) c.__index=c
function c:new(o)
local o=o or
setmetatable(o,c)
return o
endreturn c
endnamed=
function named: getname(
)return self.name
endfunction named: setname(n)
self.name=n
endaccount=
nameaccount=createclass(named,account)
account=nameaccount:new(
) print(account:getname(
))
分析下這段**,多重繼承的類,它的例項建立是基於多個父類的,那麼就需要乙個特殊的方法createclass,而且是可變長引數,記錄所有父類在parents這個table裡,然後給它的__index方法做乙個特殊處理,就是在parents中遍歷查詢基類方法。當我們建立乙個繼承與named和account的例項後,去呼叫getname方法時自身並沒有getname方法,然後它會去找到它的原表和元方法_index,會在parents裡遍歷找到getname方法,然後去呼叫。
今天的學習筆記就記錄到這~加油!
OSGi學習摘記
最近在學習osgi框架,這篇部落格就當做學習筆記吧。及時更新。osgi是基於不同classloader載入不同的資源模組,而以前的開源框架,例如 hibernate spring sturts等都是基於統一管理和唯一的classloader來設計開發。所以osgi在整合其他框架時需要做特殊處理。im...
lib檔案學習摘記
lib有靜態lib和動態lib之分。在windows上,lib的字尾為lib,在linux上,靜態lib的字尾為a和動態lib字尾為so。1 lib是編譯時需要的,dll是執行時需要的。如果要完成源 的編譯,有lib就夠了。如果也使動態連線的程式執行起來,有dll就夠了。在開發和除錯階段,當然最好都...
perl學習摘記4
模式匹配由反斜線包含 def 即模式def 檢驗匹配是否成功 result var abc 若在該字串中找到了該模式,則返回非零值,即true,不匹配則返回0,即false。則相反 模式中的特殊字元 字元 意味著乙個或多個相同的字元,如 de f 指def deef deeeeef等。它盡量匹配盡可...