Lua中沒有類的概念,但我們可以利用Lua本身的語言特性來實現(xiàn)類。
下文將詳細的解釋在Lua中實現(xiàn)類的原理,涉及到的細節(jié)點將拆分出來講,相信對Lua中實現(xiàn)類的理解有困難的同學將會釋疑。
類是什么?
想要實現(xiàn)類,就要知道類到底是什么。
在我看來,類,就是一個自己定義的變量類型。它約定了一些它的屬性和方法,是屬性和方法的一個集合。
所有的方法都需要一個名字,即使是匿名函數(shù)實際上也有個名字。這就形成了方法名和方法函數(shù)的鍵值映射關系,即方法名為鍵,映射的值為方法函數(shù)。
比如說有一個類是人,人有一個說話的方法,那就相當于,人(Person)是一個類,說話(talk)是它的一個方法名,說話函數(shù)是它的實際說話所執(zhí)行到的內容。
人也有一個屬性,比如性別,性別就是一個鍵(sex),性別的實際值就是這個鍵所對應的內容。
理解了類實際上是一個鍵值對的集合,我們不難想到用Lua中自帶的表來實現(xiàn)類。
實例是什么?
如果理解了類實際就是一個鍵值映射的表,那么我們再來理解實例是什么。
實例就是具有類的屬性和方法的集合,也是一個表了。聽起來好像和類差不多?
類全局只有一個集合,相當于上帝,全局只有一塊內存;而實例就普通了,普天之下有那么多人,你可以叫A說一句話,A便執(zhí)行了他的說話方法,但是不會影響B(tài)的說話。因為他們是實例,彼此分配著不同的內存。
說了那么多廢話,其實實例就是由類創(chuàng)建出來的值,試著把類想象成類型而不是類。
兩個語法糖
試著創(chuàng)建一個人類 Person
以上代碼將Person初始化為一個表,這個表擁有一個為name的鍵,其默認值是"這個人很懶"。
說成白話就是人類擁有一個叫名字的屬性。
那就再賦予人類一個說話的功能吧。
好了,只要調用,Person.talk(Person, "你好"),將會打印出:這個人很懶說:你好。
不過在寫程序時,大家都習慣把function放在前面,這就是函數(shù)的語法糖:
當然嘴巴都是長在自己身上的,說話只能自己說,不可能自己張嘴別人說話,所以每次都傳個self參數(shù)實在是有點不美觀,于是冒號語法糖上場。
我們還可以這么定義人類的說話功能:
但是函數(shù)體內,卻依然可以使用self,在使用:代替.時,函數(shù)的參數(shù)列表的第一個參數(shù)不再是words,Lua會自動將self做為第一個參數(shù)。這個self參數(shù)代表的意思就是這個函數(shù)的實際調用者。
所以我們調用Person:talk("你好")與Person.talk(Person, "你好")是等價的,這就是冒號語法糖帶來的便利。
如何查找表中的元素?
下面我們需要理解在Lua的表中是怎么查找一個鍵所對應的值的。
假設我們要在表p中查找talk這個鍵所對應的值,請看下面的流程圖:
理解以上內容是本文的重點,反復閱讀直至你記住了。
可以看到,由于metatable和__index這兩個神奇的東西,Lua能在當前表中不存在這個鍵的時候找到其返回值。
下面將會講一講metatable這個語言特性。
對metatable的理解
metatable是什么?
metatable的中文名叫做元表。它不是一個單獨的類型,元表其實就是一個表。
我們知道在Lua中表的操作是有限的,例如表不能直接相加,不能進行比較操作等等。
元表的作用就是增加和改變表的既定操作。只有設置過元表的表,才會受到元表的影響而改變自身的行為。
通過全局方法setmetatable(t, m),會將表t的元表設置為表m。通過另一個全局方法getmetatable(t)則會返回它的元表m。
注意:所有的表都可以設置元表,然而新創(chuàng)建的空表如果不設置,是沒有元表的。
元方法
元表作為一個表,可以擁有任意類型的鍵值對,其真正對被設置的表的影響是Lua規(guī)定的元方法鍵值對。
這些鍵值對就是Lua所規(guī)定的鍵,比如前面說到的__index,__add,__concat等等。這些鍵名都是以雙斜杠__為前綴。其對應的值則為一個函數(shù),被稱為元方法(metamethod),這些元方法定義了你想對表自定義的操作。
例如:前面所說的__index鍵,在Lua中它所對應的元方法執(zhí)行的時機是當查找不存在于表中的鍵時應該做的操作??紤]以下代碼:
pos表中本沒有z這個鍵,通過設置pos的元表為m,并設置m的__index對應的方法,這樣所有取不到的鍵都會返回“undefined”了。
以上我們了解到,元表的__index屬性實際上是給表配備了找不到鍵時的行為。
注意:元表的__index屬性對應的也可以為一個表。
再舉個栗子,希望能夠加深對元表和元方法的理解,__add鍵,考慮以下代碼:
表本身是不能用+連起來計算的,但是通過定義元表的__add的方法,并setmetatable到希望有此操作的表上去,那些表便能進行加法操作了。
因為元表的__add屬性是給表定義了使用+號時的行為。
類的實現(xiàn)手段
好,假設前面的內容你都沒有疑問的閱讀完畢話,我們開始進入正題。
請先獨立思考一會,我們該怎么去實現(xiàn)一個Lua的類?
思考ing…
種種鋪墊后,我們的類是一個表,它定義了各種屬性和方法。我們的實例也是一個表,然后我們類作為一個元表設置到實例上,并設置類的__index值為自身。
例如人類:
為了方便,我們給人類一個創(chuàng)建函數(shù)create:
這樣我們可以很方便用Person類創(chuàng)建出pa和pb兩個實例,這兩個實例都具備Person的屬性和方法。
以上便是Lua實現(xiàn)一個類的方法,至于類的繼承,當成一次練習吧,請大家思考~
上一篇:Lua table簡明總結
下一篇:編寫高性能Lua代碼的方法