2012-03-08 67 views
5

我想了解這個函數做什麼。任何人都可以向我解釋這個嗎?試圖瞭解這個lua片段

function newInstance (class) 
    local o = {} 
    setmetatable (o, class) 
    class.__index = class 
    return o 
end 

它被稱爲是這樣的:

self = newInstance (self) 
+0

請人提供更好的標題這個問題,因爲我認爲這將有助於一些開發商在那裏。 – chchrist 2012-03-09 09:25:20

回答

6

這個功能顯然是用來提供OOP的Lua中的一個變種(有點邋遢在我看來)。

這是一個班的工廠。

可能被改寫如下,爲了清楚:

C = { } 

C.foo = function(self) -- just some method, so class would not be empty 
    print("foo method called", tostring(self)) 
end 

C.__index = C -- (A) 

function newInstance(class) 
    return setmetatable({ }, class) -- (B) 
end 

現在,如果我們創建C的兩個新實例,我們清楚地看到,無論是有一個方法foo(),但不同的自我:

o1 = newInstance(C) 
o1:foo() --> foo method called table: 0x7fb3ea408ce0 

o2 = newInstance(C) 
o2:foo() --> foo method called table: 0x7fb3ea4072f0 

foo的方法是相同的:

print(o1.foo, o2.foo, o1.foo == o2.foo and "equal" or "different") 
--> function: 0x7fb3ea410760 function: 0x7fb3ea410760 equal 

這是因爲表C(所述 「類」)是__index(A)以上)的元數據o1o2,設置在(B)中。但o1o2實際上是兩個不同的表格,創建於(B)(「類實例」或「對象」)。

注意:我們設置C.__index等於C本身在(A),所以我們將重用一個表。以下具有相同的效果:

prototype = { } 

prototype.foo = function(self) -- just some method, so class would not be empty 
    print("foo method called", tostring(self)) 
end 

C = { __index = prototype } 

function newInstance(class) 
    return setmetatable({ }, class) 
end 

o = newInstance(C) 
1

這是用來在Lua中實現面向對象的行爲。 Lua使用基於原型的繼承(類似於Javascript)而不是基於類的繼承(如Java或C++)。 這個想法是,所有的類方法都是作爲原型對象的一部分實現的,並且在調用時繼承對象委託給原型。

例如,假設你想有一個類myClass提供的方法getMagicNumber

local myClass = { 
    getMagicNumber = function(self) 
     return self.theNumber; 
    end }; 

local obj = newInstance(myClass); 
obj.theNumber = 42; 
print(obj:getMagicNumber()); -- supposed to return 42 

這是怎樣的一個簡單的例子,但我希望你的想法。會發生什麼事情是這樣的:newInstance創建一個新的表,它的metatable指向myClass,並且還確保metatable的__index字段也指向myClass。 正如__index上的Lua手冊所述,當您現在嘗試在該新表上調用getMagicNumber時,會發生以下情況:第一個Lua嘗試在obj表中查找字段getMagicNumber。由於該表是空的,因此它現在搜索該表的__index表(myClass)。由於該字段在那裏找到,它現在調用myClass中的函數。

Programming in Lua如果您需要了解更多信息,請詳細討論此機制。

1

你並不孤單,我花了相當一段時間來琢磨這段代碼。下面是我的解釋

每個表只能有一個netatable,元表可以存儲之間按名稱索引的其他東西的功能,並setmetatable集的元表很自然的價值。

line class._index = ..是魔法發生的地方。

當您嘗試調用一個函數使用self.fn1(),然後LUA查找在自我的名稱FN1。如果它找不到它,那麼它在表格__index中查找self的metatable,並在存儲的表中查找'fn1'。

現在你的例子中的metatable for self是class,所以lua在metatable(class)中尋找一個__index條目來查看錶中是否有名爲fn1的函數,並且有返回。您需要將類的__index設置回自己,以便lua將查看相同的metatable - 令人困惑的嘿。 (作爲__index的賦值只需要發生一次,但由於某種原因,它總是在所有lua示例中的新運算符中完成的 - 我將它放在我的類中的新運算符之外 - 節省了幾個循環)

然後你返回新表o,lua是垃圾收集,所以每次返回一個本地創建一個新表。

function newInstance (class) 
    local o = {} 
    setmetatable (o, class) 
    class.__index = class 
    return o 
end 

心連心