lua學習隨筆 1

2021-06-26 07:56:27 字數 2799 閱讀 6684

最近在用lua寫遊戲,用的是quick-cocos2dx,研究了一下它的機制,或者說是tolua++的機制吧,怕以後忘了,寫在這兒做下記錄。

首先,lua最強大的型別就是table,它可以儲存任何變數,number、boolean、string,甚至可以儲存table。table是乙個hash表,也就是key-value儲存方式。在c中lua所有的變數表示均為乙個結構體。lua是c實現的,所以對於入棧出棧來說,任意型別的size必須相等,不然怎麼實現呢?也的確如此,簡而言之,lua的型別其實是乙個固定大小的記憶體加上固定大小的型別描述。就當32位吧,就理解成void* pdata + unsigned int 吧。無符號整形儲存的是lua變數的型別,void*就是型別的值啦。

對於普通的非gc型別,那麼void*的值就是變數的值。比如number型別(實現為c中的float),light userdata型別。它們不被gc所控制,在lua中作為引數或者返回值的傳遞也就是普通的值複製模式。

對於gc型別(string, userdata, table, closure),那麼void*就是對應型別結構的指標。這裡最主要就是研究了下userdata和table的不同,因為用cocos2dx通過tolua++匯出的類物件時候,因為obj.*** = ***的寫法很多,所以就一直在問,到底userdata是不是也算是乙個table?為何它具備了table所有的key-value儲存功能?

其實userdata是乙個記憶體塊,也是乙個預定義的結構體。因為涉及到gc操作,它和table、string、closure一樣,都有乙個gc所具有的結構頭。然後就是基本資訊了,比如分配的size等等。當你分配size大小的userdata時候,會分配乙個sizeof(userdata)+size大小的記憶體塊,前面是userdata自身的結構資訊,後續就是你可以操作的size大小的記憶體了,你可以儲存你要儲存的資料進裡面。在tolua++匯出c++物件的時候,也就是把c++物件的指標儲存在了裡面。

所以對於lua任意型別來說,入棧出棧都是push or pop乙個size固定的結構,這樣理解後很多東西也不用鑽牛角尖了。

前面提到的userdata是實現lua物件導向機制的非常重要的型別。當然牽扯到實現物件導向,tolua++的實現中還有乙個非常重要的東西就是元表。元表(metatable)是乙個普通的表,它可以預設一些基本操作,當然孤立的元表沒有任何意義,它只有成為了別的表的元表時候,才會發揮作用。

對於元表的作用,下面是乙個簡單的例子。

--	table base

local base =

-- print contents

print("base")

for i, v in ipairs(base) do

print("index["..i.."] key:"..v)

end-- set metatable

local metafunc =

metafunc.__index = metafunc

setmetatable(base, metafunc)

base:invoke(1, 545)

在上述例子中,有乙個base表。然後直接看最後一句,呼叫了base表中的invoke函式。仔細看看base表的描述,沒有任何invoke函式!怎麼可以實現呼叫呢?關鍵就在於這個metatable了。上述**定義了乙個metafunc表,裡面有乙個invoke函式,並將base表的元表設定為了metafunc,讓base錶能呼叫到metafunc表中的函式。

在呼叫的過程中,先查詢base表,沒有任意invoke鍵,所以會去查詢元表,若有元表(上述為metafunc),就執行裡面的__index,這個__index是乙個元表預設的方法,也叫元方法,當元表附屬的表中沒有查詢到對應鍵的時候,就會呼叫元表中的__index。__index有兩種設法,乙個是table,乙個是函式。當設定為table的時候,就返回對應table的對應鍵值,當設為function的時候,則會呼叫該function,該呼叫會傳入兩個引數,乙個為附屬的table,乙個為鍵。不同的原方法有不同的呼叫規則,上述就是__index原方法的呼叫規則。回到上述例子,__index為表,則直接返回元表中的key=invoke的key,它是乙個function,於是回到base:invoke呼叫中,呼叫了該方法,把base中key=1的value設為545。

在上述例子中我們已經看到了元表的神奇作用。而元表則是大部分實現lua物件導向機制中最重要的乙個元素。在tolua++中,userdata和元表是實現匯出機制的基石。在tolua++中匯出乙個類,首先會為該類生成乙個元表,匯出的函式會新增到這個元表中。當在c++中push乙個物件到lua中,亦或是在lua中呼叫c++函式生成乙個c++物件匯入到lua中,都離不開這個metatable。c++中push乙個c++物件到lua中,就會生成乙個userdata,並將對應的metatable設定為自己的元表。沒錯,userdata也支援元表,由於userdata沒有table的各種特性,所以在lua中對userdata的各種操作,比如查詢鍵值都會呼叫到元表中的原方法。

要匯出的c++類的元表中,各項原方法已被tolua++繫結。在lua中的鍵值新增,就會觸發原方法__newindex,繼而呼叫到tolua++中對應的函式。當觸發了__newindex原方法的時候,tolua++會為對應的userdata生成乙個table來記錄要新增的key與value,並將這個table作為value,userdata作為key儲存到另乙個專門用於儲存的表中。這個表儲存在reg表中。這個表就是記錄了對應的userdata所新增的變數。而對userdata進行key查詢時候,也只需要在reg表中將此表取出,利用userdata作為key查詢對應的表,然後繼續通過變數名查詢對應的value,即可取出,這也是預定的__index的工作流程。

大概就這樣了吧,以後想到再繼續。

學習隨筆 1

大學四年很快就要過去了,這個學期我要做畢業設計,題目是基於twincat的機械人運動控制系統的設計。說實話,我校的機械設計製造及其自動化專業雖然在國內名列前茅,但對於本科階段的教育過於注重設計與製造,而對於其自動化的部分則有明顯輕視 也可能是因為我們沒有立足自動化的課程設計吧,反正各種課設使我具備了...

ruby學習隨筆1

函式的括號可有可無,如puts x 或puts x 為避免使用歧義,最好使用括號 在不影響函式使用的情況下可以去掉括號。語句末尾的分號可有可無,一行語句有多個語句時要用分號隔開。只有nil和false是假,其他都是真。puts直接輸出一行內容,包括回車換行 print輸出字串,但是不包含回車換行 p...

機器學習隨筆1

1.dropout技術 在訓練深度學習網路的過程中,按照一定概率將一部分神經網路單元丟棄掉,即從原始的網路中找出乙個更瘦的網路。2.機器學習主流的學習演算法分為無監督學習和監督學習。3.監督學習下的回歸問題主要 連續值得輸出,而分類問題 離散值的輸出。4.m 訓練樣本的數量 x 輸入變數 特徵 y ...