前言
在非常非常詳細(xì)的Lua面向?qū)ο螅ㄒ唬砼c元方法中說完了一些基礎(chǔ)概念拴竹,這些是我們使用Lua模擬面向?qū)ο蟮幕A(chǔ)唐础,但是在真正的實(shí)際開發(fā)中我們的代碼肯定是不能像上一篇那樣寫的箱歧,這樣可讀性太差了,而且冗余的代碼非常多一膨,每次
setmetatable
都看起來很長很麻煩呀邢,所以為了本篇介紹的一些語法會(huì)讓我們的代碼更加貼近實(shí)際開發(fā)的習(xí)慣。在這里我有一個(gè)建議豹绪!就是我們剛開始接觸lua中的self
的時(shí)候价淌,先不要從更高更次的抽象去理解(什么這樣代表靜態(tài)方法呀,那樣代表實(shí)例方法呀瞒津,什么指向調(diào)用者自身啊之類的)蝉衣,我們還是返璞歸真,從table
的角度去理解巷蚪,相信很快就能理解了病毡!
1.更簡潔的設(shè)置元表
首先先簡化上一篇文章中的setmetatable
的寫法,在上一篇文章中屁柏,我們?yōu)槠胀ū砺暶饕粋€(gè)帶有__index
元方法的元表是這樣寫的
_M= { __ index = { key2 = "value2" }}
mytable = setmetatable({},_M)
emmmm啦膜,這樣寫雖然好理解,但是這樣其實(shí)是多出了一個(gè)由__index
指向的匿名表淌喻。所以我們修改一下寫法
_M= { key2 = "value2" }
mytable = setmetatable({},_M)
_M.__index=_M
看官們細(xì)品一下這兩種寫法的異同僧家,當(dāng)我們嘗試索引一個(gè)mytable普通表中沒有的key
的時(shí)候,就去去索引元表的__index
似嗤,發(fā)現(xiàn)__index
指向的是一個(gè)table
_M啸臀,所以就會(huì)繼續(xù)在_M中索引。
眾所周知烁落,Lua的table
中的value
值是可以指向一個(gè)function
的乘粒,那現(xiàn)我們將對_M的賦值放到一個(gè)初始化方法中,這樣在我們需要用到這個(gè)表之前先調(diào)用一下這個(gè)初始化方法然后再使用伤塌,我們暫且把這個(gè)初始化方法起名叫New
吧灯萍。所以代碼如下:
_M={}
mytable = setmetatable({},_M)
function _M.New()
_M.name='my name is _M.'
_M.age=22
_M.__index=_M
end
然后我們只需要在打算訪問mytable
之前,先調(diào)用一次_M.New()
完成對表中一些值的初始化每聪,然后就可訪問了旦棉,嗯是不是有點(diǎn)我們新建對象內(nèi)味了齿风。
_M.New()
print(mytable.name) --輸出my name is _M.
print(mytable.age) --輸出22
OK,打住绑洛,我們先繼續(xù)講一講點(diǎn)號(hào)和冒號(hào)還有self
2.最普通的點(diǎn)號(hào)調(diào)用
就像上面例子中的New()
方法救斑,我們最簡單自然調(diào)用它的辦法就是_M.New()
,在一般情況下這樣調(diào)用一個(gè)方法已經(jīng)能達(dá)到我們的目的了真屯,比如我在一個(gè)table
中添加一個(gè)很普通的輸出方法脸候,就這樣直接調(diào)用這個(gè)tableA.Print()
就能達(dá)到我們輸出的效果了。
tableA = {}
function tableA.Print()
print('output from tableA')
end
tableA.Print()
但是如果我往tableA
中添加了幾個(gè)屬性绑蔫,然后我希望在PrintA
中去訪問一下這幾個(gè)屬性运沦,那我們需要怎么辦呢,也很簡單配深,就直接在方法里面顯式的聲明就好了嘛携添!
tableA = {}
--為這個(gè)table添加一個(gè)屬性
tableA.keyA='valueA'
function tableA.Print()
print(tableA.keyA) --輸出valueA
end
tableA.Print()
這看起來并沒有self
和冒號(hào)什么事對嗎。那我們現(xiàn)在改一改上面的代碼篓叶,我新建一個(gè)表tableB
然后把tableA
設(shè)置為其元表烈掠。然后用tableB
去調(diào)用Print()
方法(不知道為什么能調(diào)用成功的同學(xué)可以去上一節(jié)看看就知道了~),依舊可以輸出valueA
tableA = {}
--為這個(gè)table添加一個(gè)屬性
tableA.keyA='valueA'
tableA.__index=tableA
function tableA.Print()
print(tableA.keyA)
end
--將tableA設(shè)置為tableB元表缸托,然后調(diào)用一下Print()
tableB=setmetatable({},tableA)
tableB.Print()--輸出valueA
但是現(xiàn)在我想在tableB
中也添加一個(gè)keyA
(沒想到吧O虿妗),然后這次我想讓Print()
打印出tableB
中'keyA'的值了嗦董,這時(shí)候我們的點(diǎn)號(hào)就束手無策了。
tableA = {}
--為這個(gè)table添加一個(gè)屬性
tableA.keyA='valueA'
tableA.__index=tableA
function tableA.Print()
print(tableA.keyA)
end
--將tableA設(shè)置為tableB元表瘦黑,然后調(diào)用一下Print()
tableB=setmetatable({ keyA = 'valueB' },tableA)
tableB.Print()--輸出valueA
3.self和冒號(hào)來了
想要實(shí)現(xiàn)我們上面的需求京革,self關(guān)鍵字就可以輕而易舉的達(dá)到了!我們稍微改變一下Print()
的代碼幸斥。大家可以看到匹摇,我只是簡單地加入了一個(gè)名為self
的參數(shù),并且把對tableA.keyA
的訪問甲葬,換成了對self.keyA
的訪問廊勃。
--修改前的代碼
function tableA.Print()
print(tableA.keyA)
end
tableB=setmetatable({ keyA = 'valueB' },tableA)
tableB.Print()--輸出valueA
--修改后的代碼
function tableA.Print(self)
print(self.keyA)
end
tableB=setmetatable({ keyA = 'valueB' },tableA)
tableB.Print(tableB)--輸出valueB
經(jīng)過這樣修改后我們再通過tableB.Print(tableB)
,就能夠輸出tableB.keyA
的值了经窖。至此坡垫,self
的作用已經(jīng)很明確了,
self
代表的就是作為參數(shù)傳入的那個(gè)table
當(dāng)我們清楚了這點(diǎn)后,對于冒號(hào)調(diào)用的理解也就水到渠成了画侣,對于上面tableB.Print(tableB)
這樣的寫法冰悠,如果我們想省略掉參數(shù)里的tableB
,只需要改為tableB:Print()
這樣就可以了
冒號(hào)調(diào)用配乱,代表默認(rèn)將調(diào)用者作為self參數(shù)溉卓,所以我們可以不用顯式的將調(diào)用者作為參數(shù)傳遞了
最后再多嘴說一種情況皮迟,加深一下對self
的理解。如果現(xiàn)在我仍然想通過tableB
來調(diào)用Print()
桑寨,但是伏尼,我這次不想輸出tableB
的keyA
了,我想輸出tableA
的'keyA'了嘿嘿(這嘴臉有沒有讓你們想起自己的PM或者策劃)尉尾,這也好辦爆阶,我們只需要將tableA
作為self參數(shù)傳入就可以了,