2013-03-17 47 views
2

我對Lua中的物體不太瞭解,所以請耐心等待。
示例代碼:更改對象中表的值會更改所有對象的值。我如何才能讓它只針對特定對象進行更改?

Colors = { 
     primary = "BF2626", 
     primaryGradient = {"CC2929", "B32424"} 
     } 

function Colors:new(o) 
    o = o or {} 
    setmetatable(o, self) 
    self.__index = self 
    return o 
end 

function Colors:setPrimaryGradient() 
    self.primaryGradient[1] ="Changed" 
end 

function Colors:setPrimary() 
    self.primary ="00FF00" 
end 

a =Colors:new() 
b =Colors:new() 

b:setPrimaryGradient() 
b:setPrimary() 

print(a.primaryGradient[1]) 
print(b.primaryGradient[1]) 
print(a.primary) 
print(b.primary) 

輸出:

Changed 
Changed 
BF2626 
00FF00 

我在做什麼錯?
爲什麼變量主要爲保留每個對象的值,但表不?
謝謝。

回答

3

您的new函數爲空表設置了元表。此metatable具有功能內部數據。它還設置了一個__index metamethod。這很重要。

您的setPrimaryGradient方法需要self作爲隱式參數。在這種情況下,self是在new中創建的新表。你的問題在這裏:

self.primaryGradient[1]不是一個單一的構造。它是兩個獨立的操作。讓我們來寫下Lua如何使用它:self["primaryGradient"][1]。看到問題了嗎?

第一部分,self["primaryGradient"]將檢查self表並獲得它的primaryGradient成員。問題是,因爲self有一個__index metamethod,並且self中沒有primaryGradient成員,所以它將直接使用__index元方法。所以它將從metatable獲得primaryGradient。 metatable即共享

[1]部分將隨後的元表的構件上執行,和一個值將從元表被存儲在primaryGradient的第一個元素。

setPrimary之所以沒有出現同樣的問題很簡單。 self.primary是一個操作。因爲它是一個表訪問,然後是賦值操作,所以Lua不會使用metamethod。它將使用__newindex metamethod。由於您沒有爲self的metatable定義一個,因此它將使用默認邏輯:在self中創建一個新成員並設置其值。

原因setPrimaryGradient不使用__newindex是因爲它。只是不能訪問self。它使用__newindex訪問self["primaryGradient"];只有最後表訪問獲得__newindex調用。

如果要使用一些可以修改的默認值初始化您的類型,則需要複製這些值。有時你不能僅僅參考全局的。那麼,你可以,但建立起來會很痛苦。

+0

這是有道理的。 謝謝Nicol! – 2013-03-17 01:18:11

1

這個問題可以很容易地固定在這樣:

Colors = { 
     primary = "BF2626", 
     primaryGradient = {"CC2929", "B32424"} 
     } 
Colors.primaryGradient.__index = Colors.primaryGradient 

function Colors:new(o) 
    o = o or {primaryGradient = setmetatable({}, self.primaryGradient)} 
    setmetatable(o, self) 
    self.__index = self 
    return o 
end 
+0

感謝你也是葉戈爾。 – 2013-03-17 21:34:41