亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > 綜合 > 正文

Lua中類的實現原理探討(Lua中實現類的方法)

2024-07-21 23:04:14
字體:
來源:轉載
供稿:網友

Lua中沒有類的概念,但我們可以利用Lua本身的語言特性來實現類。

下文將詳細的解釋在Lua中實現類的原理,涉及到的細節點將拆分出來講,相信對Lua中實現類的理解有困難的同學將會釋疑。

類是什么?

想要實現類,就要知道類到底是什么。

在我看來,類,就是一個自己定義的變量類型。它約定了一些它的屬性和方法,是屬性和方法的一個集合。

所有的方法都需要一個名字,即使是匿名函數實際上也有個名字。這就形成了方法名和方法函數的鍵值映射關系,即方法名為鍵,映射的值為方法函數。

比如說有一個類是人,人有一個說話的方法,那就相當于,人(Person)是一個類,說話(talk)是它的一個方法名,說話函數是它的實際說話所執行到的內容。

人也有一個屬性,比如性別,性別就是一個鍵(sex),性別的實際值就是這個鍵所對應的內容。

理解了類實際上是一個鍵值對的集合,我們不難想到用Lua中自帶的表來實現類。

實例是什么?

如果理解了類實際就是一個鍵值映射的表,那么我們再來理解實例是什么。

實例就是具有類的屬性和方法的集合,也是一個表了。聽起來好像和類差不多?

類全局只有一個集合,相當于上帝,全局只有一塊內存;而實例就普通了,普天之下有那么多人,你可以叫A說一句話,A便執行了他的說話方法,但是不會影響B的說話。因為他們是實例,彼此分配著不同的內存。

說了那么多廢話,其實實例就是由類創建出來的值,試著把類想象成類型而不是類。

兩個語法糖

試著創建一個人類 Person

 

復制代碼 代碼如下:

Person = {name="這個人很懶"}

 

以上代碼將Person初始化為一個表,這個表擁有一個為name的鍵,其默認值是"這個人很懶"。

說成白話就是人類擁有一個叫名字的屬性。

那就再賦予人類一個說話的功能吧。

 

復制代碼 代碼如下:

Person.talk = function(self, words)
    print(self.name.."說:"..words)
end

以上代碼在Person表中加入一個鍵值對,鍵為talk,值為一個函數。

 

好了,只要調用,Person.talk(Person, "你好"),將會打印出:這個人很懶說:你好。

不過在寫程序時,大家都習慣把function放在前面,這就是函數的語法糖:

 

復制代碼 代碼如下:

function Person.talk(self, words)
    print(self.name.."說:"..words)
end

這與上面的函數定義是等價的,但是這么寫你就很難看出來talk其實是Person表中的一個鍵,其對應的值為一個函數。

 

當然嘴巴都是長在自己身上的,說話只能自己說,不可能自己張嘴別人說話,所以每次都傳個self參數實在是有點不美觀,于是冒號語法糖上場。

我們還可以這么定義人類的說話功能:

 

復制代碼 代碼如下:

function Person:talk(words)
    print(self.name.."說:"..words)
end

這與上面兩段代碼都是等價的,它的變化是少了self的參數,將點Person.talk改為了冒號Person:talk。

 

但是函數體內,卻依然可以使用self,在使用:代替.時,函數的參數列表的第一個參數不再是words,Lua會自動將self做為第一個參數。這個self參數代表的意思就是這個函數的實際調用者。

所以我們調用Person:talk("你好")與Person.talk(Person, "你好")是等價的,這就是冒號語法糖帶來的便利。

如何查找表中的元素?

下面我們需要理解在Lua的表中是怎么查找一個鍵所對應的值的。

假設我們要在表p中查找talk這個鍵所對應的值,請看下面的流程圖:

復制代碼 代碼如下:

p中有沒有talk這個鍵? 有 --> 返回talk對應的值
        |
       沒有
        |
p中是否設置過metatable? 否 -->  返回nil
        |
        有
        |
在p的metatable中有沒有__index這個鍵? 沒有 -->  返回nil
        |
        有
        |     
在p的metatable中的__index這個鍵對應的表中有沒有talk這個鍵? 沒有 --> 返回nil
        |
        有,返回getmetatable(p).__index.talk

 

理解以上內容是本文的重點,反復閱讀直至你記住了。

可以看到,由于metatable和__index這兩個神奇的東西,Lua能在當前表中不存在這個鍵的時候找到其返回值。

下面將會講一講metatable這個語言特性。

對metatable的理解

metatable是什么?

metatable的中文名叫做元表。它不是一個單獨的類型,元表其實就是一個表。

我們知道在Lua中表的操作是有限的,例如表不能直接相加,不能進行比較操作等等。

元表的作用就是增加和改變表的既定操作。只有設置過元表的表,才會受到元表的影響而改變自身的行為。

通過全局方法setmetatable(t, m),會將表t的元表設置為表m。通過另一個全局方法getmetatable(t)則會返回它的元表m。

注意:所有的表都可以設置元表,然而新創建的空表如果不設置,是沒有元表的。

元方法

元表作為一個表,可以擁有任意類型的鍵值對,其真正對被設置的表的影響是Lua規定的元方法鍵值對。

這些鍵值對就是Lua所規定的鍵,比如前面說到的__index,__add,__concat等等。這些鍵名都是以雙斜杠__為前綴。其對應的值則為一個函數,被稱為元方法(metamethod),這些元方法定義了你想對表自定義的操作。

例如:前面所說的__index鍵,在Lua中它所對應的元方法執行的時機是當查找不存在于表中的鍵時應該做的操作??紤]以下代碼:

復制代碼 代碼如下:

--定義元表m
m = {}
--定義元表的__index的元方法
--對任何找不到的鍵,都會返回"undefined"
m.__index = function ( table, key )
  return "undefined"
end  
 
--表pos
pos = {x=1, y=2}
--初始沒有元表,所以沒有定義找不到的行為
--因為z不在pos中,所以直接返回nil
print(pos.z) -- nil
--將pos的元表設為m
setmetatable(pos, m)
--這是雖然pos里仍然找不到z,但是因為pos有元表,
--而且元表有__index屬性,所以執行其對應的元方法,返回“undefined”
print(pos.z) -- undefined

 

pos表中本沒有z這個鍵,通過設置pos的元表為m,并設置m的__index對應的方法,這樣所有取不到的鍵都會返回“undefined”了。

以上我們了解到,元表的__index屬性實際上是給表配備了找不到鍵時的行為。

注意:元表的__index屬性對應的也可以為一個表。

再舉個栗子,希望能夠加深對元表和元方法的理解,__add鍵,考慮以下代碼:

復制代碼 代碼如下:

--創建元表m,其中有__add鍵和其定義的方法
local m = {
  __add = function(t1, t2)
    local sum = {}
    for key, value in pairs(t1) do
      sum[key] = value
    end
 
    for key, value in pairs(t2) do
      if sum[key] then
        sum[key] = sum[key] + value
      else
        sum[key] = value
      end
    end
    return sum
  end
}
 
--將table1和table2都設置為m
local table1 = setmetatable({10, 11, 12}, m)
local table2 = setmetatable({13, 14, 15}, m)
 
--表本來是不能執行 + 操作的,但是通過元表,我們做到了!
for k, v in pairs(table1 + table2) do
  print(k, v)
end
--print
--1 23
--2 25
--3 27

 

表本身是不能用+連起來計算的,但是通過定義元表的__add的方法,并setmetatable到希望有此操作的表上去,那些表便能進行加法操作了。

因為元表的__add屬性是給表定義了使用+號時的行為。

類的實現手段

好,假設前面的內容你都沒有疑問的閱讀完畢話,我們開始進入正題。

請先獨立思考一會,我們該怎么去實現一個Lua的類?

思考ing…

種種鋪墊后,我們的類是一個表,它定義了各種屬性和方法。我們的實例也是一個表,然后我們類作為一個元表設置到實例上,并設置類的__index值為自身。

例如人類:

復制代碼 代碼如下:

--設置Person的__index為自身
Person.__index = Person  
 
--p是一個實例
local p = {}
 
--p的元表設置為Person
setmetatable(p, Person)
 
p.name = "路人甲"
 
--p本來是一個空表,沒有talk這個鍵
--但是p有元表,并且元表的__index屬性為一個表Person
--而Person里面有talk這個鍵,于是便執行了Person的talk函數
--默認參數self是調用者p,p的name屬性為“路人甲”
p:talk("我是路人甲")
 
--于是得到輸出
--路人甲說:我是路人甲

 

為了方便,我們給人類一個創建函數create:

 

復制代碼 代碼如下:

function Person:create(name)
    local p = {}
    setmetatable(p, Person)
    p.name = name
    return p
end
 
local pa = Person:create("路人甲")
local pb = Person:create("路人乙")
pa:talk("我是路人甲") --路人甲說:我是路人甲
pb:talk("我是路人乙") --路人乙說:我是路人乙

 

這樣我們可以很方便用Person類創建出pa和pb兩個實例,這兩個實例都具備Person的屬性和方法。

以上便是Lua實現一個類的方法,至于類的繼承,當成一次練習吧,請大家思考~

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
中文字幕日韩有码| 8090成年在线看片午夜| 丝袜情趣国产精品| 91网在线免费观看| 欧美精品videosex牲欧美| 久久久黄色av| 国产一区二区黄| 日本免费一区二区三区视频观看| 午夜精品在线视频| 日韩免费在线看| 国产激情久久久久| 国产精品揄拍一区二区| 成人免费观看49www在线观看| 国产一区二区三区在线观看网站| 国产色视频一区| 国产va免费精品高清在线观看| 美乳少妇欧美精品| 中文字幕在线看视频国产欧美在线看完整| 日韩中文理论片| 免费99精品国产自在在线| 亚洲性xxxx| 国产成人在线亚洲欧美| 亚洲欧美一区二区精品久久久| 色婷婷**av毛片一区| 久热精品在线视频| 亚洲成人久久网| 欧美午夜无遮挡| 中文字幕亚洲第一| 日韩免费观看av| 久久香蕉国产线看观看av| 成人黄色生活片| 欧美裸体男粗大视频在线观看| 91精品国产成人| 久久91精品国产91久久跳| 最近2019中文字幕在线高清| 久久久久国产视频| 国产精品美女免费| 欧美在线www| 精品国产一区二区三区久久狼5月| 日本伊人精品一区二区三区介绍| 亚洲人成电影网| 久久99亚洲精品| 亚洲欧洲美洲在线综合| 国产丝袜精品第一页| 亚洲精品一区二区三区不| 久久91精品国产91久久跳| 福利一区视频在线观看| 一区三区二区视频| 亚洲日韩中文字幕| 91社影院在线观看| 亚洲电影免费观看高清完整版在线| 亚洲国产一区二区三区在线观看| 国产经典一区二区| 97人人做人人爱| 亚洲国产欧美一区二区丝袜黑人| 亚洲精品中文字幕女同| 日韩精品在线观看一区二区| 国产精品丝袜久久久久久不卡| 国产成人亚洲精品| 91美女片黄在线观看游戏| 国产精品久久久久久超碰| 91av视频在线| 蜜月aⅴ免费一区二区三区| 国产精品扒开腿做爽爽爽视频| 欧美精品做受xxx性少妇| 欧美资源在线观看| 亚洲free性xxxx护士白浆| 日本午夜精品理论片a级appf发布| 上原亚衣av一区二区三区| 2020国产精品视频| 欧美国产日本高清在线| 国产九九精品视频| 久久免费视频网站| 91精品免费视频| 久久激情视频免费观看| 久久久免费观看| 久久精品电影网站| 日韩视频免费大全中文字幕| 日日狠狠久久偷偷四色综合免费| 亚洲欧美国产一区二区三区| 92裸体在线视频网站| 精品免费在线视频| 91久热免费在线视频| 亚洲深夜福利网站| 成人黄色片在线| 亚洲国产小视频| 国产午夜精品视频免费不卡69堂| 日韩av在线不卡| 国产亚洲美女精品久久久| 国产精品一区二区在线| 亚洲第一av在线| 色吧影院999| 亚洲综合中文字幕在线观看| 亚洲人av在线影院| www.99久久热国产日韩欧美.com| 久久精品国产欧美激情| 成人免费网视频| 亚洲精品网址在线观看| 欧美精品在线免费播放| 日韩在线视频国产| 国产亚洲视频中文字幕视频| 国产91色在线| 在线视频精品一| 欧美一级黑人aaaaaaa做受| 亚洲国产福利在线| 欧美另类xxx| 国产精品美女www| 久久精品91久久香蕉加勒比| 国产亚洲欧美aaaa| 色黄久久久久久| 中文国产亚洲喷潮| 亚洲男人av在线| 欧美成人h版在线观看| 亚洲国产精彩中文乱码av| 亚洲国产欧美在线成人app| 亚洲欧美精品一区二区| 不卡伊人av在线播放| 国产精品久久一区| 日韩一区在线视频| 成人福利网站在线观看11| 欧美日韩国产精品一区二区不卡中文| 欧美色图在线视频| 亚洲www永久成人夜色| 中文字幕欧美日韩va免费视频| 国产精品久久久av| 亚洲а∨天堂久久精品喷水| 国产97在线|日韩| 成人欧美一区二区三区黑人| 亚洲第一中文字幕| 国产视频福利一区| 国产精品99久久99久久久二8| 精品网站999www| 黄色精品在线看| 亚洲精品少妇网址| 日韩中文字幕久久| 日韩成人av一区| 激情亚洲一区二区三区四区| 九九九久久国产免费| 日韩免费看的电影电视剧大全| 777精品视频| 97色伦亚洲国产| 成人网页在线免费观看| 国产99视频精品免视看7| 亚洲区bt下载| 久久国产精品影片| 日韩成人av网址| 亚洲最大福利网| 欧美日韩国产综合视频在线观看中文| 国产精品自拍网| 久久99亚洲热视| 久久久久久久激情视频| 亚洲福利视频久久| 91chinesevideo永久地址| 5252色成人免费视频| 欧美中在线观看| 欧美激情一区二区三区久久久| 国产精品高潮视频| 欧美电影免费看| 国产成人在线视频| 中文字幕精品www乱入免费视频| 精品久久久视频| 777国产偷窥盗摄精品视频| 亚洲欧美中文日韩在线| 在线看片第一页欧美|