非常非常詳細的Lua面向?qū)ο螅ㄒ唬砼c元方法

前言

新的項目終于準備要真正開始使用Lua進行開發(fā)了滥比,所以筆者最近也開始了對Lua的學習盗扇,從以前的強類型的靜態(tài)語言C#,到動態(tài)腳本語言寥假,多少會有一點點不習慣市框。除此之外,思考方式也會有細微的差異糕韧,畢竟Lua里并沒有類這個概念枫振。所以在接下來的幾篇文章中喻圃,我會嘗試將Lua是如何模擬類這一過程梳理清楚,畢竟是剛剛開始粪滤,很多感受比較直觀以及浮于表面斧拍,如果有什么錯誤疏漏之處,也希望各位能夠指出~


1.Lua中的table

如果說在python中一切皆對象的話杖小,那么Lua可以說是一切皆table了肆汹,table是是Lua中極其強大的數(shù)據(jù)結(jié)構(gòu),一個模塊予权,一個數(shù)組昂勉,一個字典,他們都可以用table實現(xiàn)扫腺,我們模擬面向?qū)ο缶幊谈谡眨瑃able也是必不可少的,我們的每一個對象其實也就是一個table笆环。關(guān)于luatable的介紹網(wǎng)上有非常多攒至,這里就不展開細說了~

2.元表

當我第一次接觸到Lua元表的概念時,我腦海里就一個想法“原來表還能夠這么玩”咧织。為什么需要出現(xiàn)元表這個概念,因為Lua的表實在是太萬能了籍救,對單一表操作再某些場景下很難滿足我們的需求习绢,所以元表的出現(xiàn),可以讓我們高度的自定義兩個表之間的操作蝙昙。

2.1設(shè)置元表

設(shè)置元表非常的簡單闪萄,如下代碼所示,在下文中奇颠,我將setmetatable的第一個參數(shù)所表示的表稱為普通表败去,第二個參數(shù)所表示的表為元表

mytable = {}--普通表               
mymetatable = {}--元表
setmetatable(mytable , mymetatable)--將mymetatable設(shè)置為mytable的元表

這一段代碼等價于

mymetatable = {}
mytable = setmetatable({},mymetatable)

setmetatable()為Lua的提供的內(nèi)置方法,其返回值是普通表的引用烈拒。

3.元方法

在設(shè)置了元表后圆裕,我們需要怎么操作才能發(fā)揮元表的作用呢,這就不得不提到元方法了荆几。我們首先介紹兩個使用頻率最高的元方法__index以及__newindex吓妆。我們使用一種數(shù)據(jù)結(jié)構(gòu)來存儲數(shù)據(jù),使用時無外乎兩種基本操作(元其實就是基本的意思)吨铸,讀和寫行拢,對于table來說也就是索引操作賦值操作

3.1__index

如果我們想自定義對一張普通表索引時的一些特殊行為,我們可以通過為其元表添加__index這個key來實現(xiàn)自定義(注意诞吱,是在元表中添加__index而不是直接設(shè)置__index)舟奠。設(shè)置的方式非常簡單竭缝,我們繼續(xù)使用2.1中的mytable作為例子。

3.1.1指向table的情況

mymetatable = { __ index = { key2 = "value2" }} 
mytable = setmetatable({},mymetatable)

--等價于以下代碼沼瘫,所以希望大家以后看到網(wǎng)上各種寫法時不再感到疑惑
mytable = setmetatable({},{ __ index = { key2 = "value2" })

上述代碼就在mymetatable這個表中設(shè)置了__index這個key抬纸,而這個key指向的是一個table。

__index指向的是一個table的情況下晕鹊,對普通表進行索引操作時

  • 若普通表存在該key則返回該key所指向的value
  • 若普通表不存在該key松却,則嘗試查找該普通表的元表,如果元表中沒有__index則返回nil溅话,如果有則繼續(xù)對__index所指向的表進行索引晓锻。
  • 若該key存在,則返回該key所指向的value
  • 若該key不存在飞几,則返回nil

舉個栗子砚哆,我們依然用上面的代碼,只不過在普通表中增加一個key

mymetatable = { __ index = { key2 = "value2" }} 
mytable = setmetatable({ key1 = "value1" },mymetatable)
--普通表存在key1屑墨,所以返回value1
print(mytable.key1) --輸出value1
--普通表不存在key2躁锁,__index指向的table中存在,所以返回value2
print(mytable.key2) --輸出value2
--普通表和元表都不存在key3卵史,所以返回nil
print(mytable.key3) --輸出nil

3.1.2指向function的情況

mytable = setmetatable({}, { __index = function()
  print("你正在嘗試索引mytable中沒有的key")
  end}
)
returnValue = mytable.key1 --輸出 "你正在嘗試索引mytable中沒有的key"
print(returnValue) --輸出 nil

__index還可以指向一個function

當我們試圖索引一個普通表中不存在的key時战转,如果元表中存在__index,且__index指向的是一個function以躯,那么就會去執(zhí)行這個function槐秧,索引所得到的值則是該function的返回值(上面例子代碼無返回值所以輸出為nil)

--存在返回值的情況
mytable = setmetatable({}, { __index = function()
  print("你正在嘗試索引mytable中沒有的key")
  return 58
  end}
)
returnValue = mytable.key1 --輸出 "你正在嘗試索引mytable中沒有的key"
print(returnValue) --輸出 58

3.2__newindex

與索引相對應的,如果我們想自定義對一個普通表的賦值操作忧设,就可以使用__newindex元方法刁标。其使用邏輯與__index基本相似,一樣是存在指向table址晕,或者指向function的區(qū)別膀懈。

3.2.1指向table

--指向table
mymetatable = { key2 = "value2" }
mytable = setmetatable({key1="value1"}, { __newindex =mymetatable})
print(mytable.key1) --輸出 value1
mytable.key1="modified1"
print(mytable.key1) --輸出modified1

mytable.key2="modified2"
print(mytable.key2) --輸出nil

我們首先嘗試獲取mytable中的key1,然后對其進行賦值谨垃,因為mytale中存在key1启搂,所以直接賦值即可,我們通過前后的print可以驗證這一點刘陶。如果我們嘗試對一個mytable中沒有的key進行賦值狐血,那會怎么樣呢

首先會查詢該普通表的元表中是否有__newindex這個key

  • 若沒有,則直接在普通表中增加這個key易核,對其進行賦值操作
  • 若存在__newindex匈织,且其指向的是一個table,那么就會在__newindex指向的table中增加這個key,并且進行賦值

有一個非常容易引起迷惑的點我們需要注意的是
__index與__newindex的操作是完全獨立的!
所以一開始可能會有些疑惑缀匕,為什么上面代碼輸出會是nil纳决,我們不是明明已經(jīng)設(shè)置了key2的值了嗎?我們確實是成功進行了賦值操作乡小,但是根據(jù)上面的邏輯阔加,因為mytable中不存在key2,所以我們實際上是對__newindex所指向的mymetatable進行了賦值操作满钟。實際上普通表是沒有任何變化的胜榔,所以我們最后一行代碼,嘗試索引mytable的key2湃番,按照3.1.1中的邏輯夭织,因為沒有設(shè)置__index方法,所以返回的會是nil吠撮。如果我們希望訪問到key2尊惰,下面的代碼就可以做到了

print(mymetatable.key2) --輸出 modified2

3.2.2指向function

--指向function
mytable = setmetatable({key1="value1"}, { __newindex = function()
                print("該表禁止增加新的key!")
end})
mytable.key2 = "value2" --輸出 "該表禁止增加新的key泥兰!"

如果__newindex指向的是function弄屡,那么在對一個普通表中不存在的key進行賦值時,會執(zhí)行這個function鞋诗。

3.2.3function帶有參數(shù)的情況

3.1.2以及3.2.2中的示例只是最基礎(chǔ)不帶參數(shù)的情況膀捷,其實在__index__newindex這兩個元方法指向function類型時,是會傳遞參數(shù)進來的削彬,直接上代碼全庸。
__index默認傳遞的兩個參數(shù)是調(diào)用該方法的table,以及嘗試訪問的key

mytable = setmetatable({}, { __index = function(t,k)
  print("你正在嘗試索引mytable中沒有的key")
  print(t,k)--輸出 table: 0x5621b1f07270  key1
  end}
)
returnValue = mytable.key1 --輸出 "你正在嘗試索引mytable中沒有的key"
print(returnValue) --輸出 nil

__newindex默認傳遞進來的是三個參數(shù)吃警,調(diào)用該方法的table糕篇,需要賦值的key以及想要賦予的value

mytable = setmetatable({key1="value1"}, { __newindex = function(t,k,v)
  print("該表禁止增加新的key啄育!")
  print(t,k,v)--輸出table: 0x55a8f8aefbb0 key2 value2
end})
mytable.key2 = "value2" --輸出 "該表禁止增加新的key酌心!"

其他的元方法

除了__index__newindex這兩個元方法外挑豌,還有很多別十分有用的元方法安券,等我后面用到的時候會陸續(xù)添加進來!

最后

理解了元表以及元方法后氓英,在下一章中侯勉,我們就可以開始在Lua中真正的去模擬面向?qū)ο笏枷胫校庋b铝阐,多態(tài)址貌,繼承的特性了!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市练对,隨后出現(xiàn)的幾起案子遍蟋,更是在濱河造成了極大的恐慌,老刑警劉巖螟凭,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件虚青,死亡現(xiàn)場離奇詭異,居然都是意外死亡螺男,警方通過查閱死者的電腦和手機棒厘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來下隧,“玉大人奢人,你說我怎么就攤上這事⊥粲担” “怎么了达传?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長迫筑。 經(jīng)常有香客問我宪赶,道長,這世上最難降的妖魔是什么脯燃? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任搂妻,我火速辦了婚禮,結(jié)果婚禮上辕棚,老公的妹妹穿的比我還像新娘欲主。我一直安慰自己,他們只是感情好逝嚎,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布扁瓢。 她就那樣靜靜地躺著,像睡著了一般补君。 火紅的嫁衣襯著肌膚如雪引几。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天挽铁,我揣著相機與錄音伟桅,去河邊找鬼。 笑死叽掘,一個胖子當著我的面吹牛楣铁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播更扁,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼盖腕,長吁一口氣:“原來是場噩夢啊……” “哼赫冬!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起溃列,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤面殖,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后哭廉,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體脊僚,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年遵绰,在試婚紗的時候發(fā)現(xiàn)自己被綠了辽幌。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡椿访,死狀恐怖乌企,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情成玫,我是刑警寧澤加酵,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站哭当,受9級特大地震影響猪腕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜钦勘,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一陋葡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧彻采,春花似錦腐缤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至特笋,卻和暖如春剃浇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背雹有。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工偿渡, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留臼寄,地道東北人霸奕。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像吉拳,于是被迫代替她去往敵國和親质帅。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354