2011-11-29 224 views
4

lua是否有一個「事件處理程序」內置或它有一個lib可用來做到這一點?Lua事件處理程序

因此,舉個例子,當「a = 100」事件發生時。

別的東西,而不是使用:

while true do 
if a == 100 then 
    [...] 
    break; 
end 
end 

還是簡單地增加睡眠吧。 「雖然真的做」只是一個例子,但它是一個可怕的例子。

+0

好吧。基本上檢查一個值,如果它滿足一個事件被調用的要求。只是不要以「ifs」的方式來做,或者像上面的「while true do」那樣做,因爲它不適合。例如,可以在任何時候滿足要求,而不是我可以調用if語句的特定部分或時間。我希望能解釋一下。 – luacoder

回答

15

Lua在單線程中運行,因此任何檢查都必須由您的代碼明確執行。

在變量變化時立即執行代碼的行爲稱爲「觀察」。

如果您在一組代碼運行的環境中編程,每(例如遊戲),您可以手動檢查。 例如:

WatchedVariables = { 
    a = 5, 
    b = 22, 
} 
WatchedVariables_cache = {} 
for k,v in pairs(WatchedVariables) do 
    WatchedVariables_cache[k] = v 
end 

function OnFrame() 
    print("NEXT FRAME! (possibly 1 second later or something)") 
    for k,v in pairs(WatchedVariables) do 
     local v_old = WatchedVariables_cache[k] 
     if v ~= v_old then 
      -- this is the "callback" 
      print(tostring(k).." changed from "..tostring(v_old).." to "..tostring(v)) 

      WatchedVariables_cache[k] = v 
     end 
    end 
end 

function SomeFunctionThatOperatesSomeTime() 
    print("about to change a, brother!") 
    WatchedVariables.a = -7 
    print("a is changed") 
end 

在下一幀中,回調代碼(打印)將被執行。 這種方法的缺點是,回調代碼不WatchedVariables.a設置爲-7後立即印刷,即:輸出將是:

about to change a, brother! 
a is changed 
NEXT FRAME! (possibly 1 second later or something) 
a changed from 5 to -7 

爲了防止這種潛在的不希望的行爲,一個設定器函數可用於,例如:

MyObject = { 
    _private_a = 5, 
    set_a = function(self, new_value_of_a) 
     self._private_a = 5 
     -- callback code 
     print("a set to "..tostring(new_value_of_a)) 
    end, 
    get_a = function(self) 
     return self._private_a 
    end 
} 

function SomeFunctionThatOperatesSomeTime() 
    print("about to change a, brother!") 
    MyObject:set_a(-7) 
    print("a is changed") 
end 

此代碼的輸出顯示回調立即運行:

about to change a, brother! 
a set to -7 
a is changed 

爲了使這更舒適,Lua提供了元表,這些行爲對程序員來說是透明的。 例子:

MyObject = { 
    __privates = { 
     a = 5, 
    } 
} 
MyObject_meta = { 
    __index = function(self, k) 
     return rawget(self, "__privates")[k] 
    end, 
    __newindex = function(self, k, v) 
     rawget(self, "__privates")[k] = v 
     -- callback code 
     print("a set to "..tostring(v)) 
    end, 
} 
setmetatable(MyObject, MyObject_meta) 

function SomeFunctionThatOperatesSomeTime() 
    print("about to change a, brother!") 
    MyObject.a = -7 
    print("a is changed") 
end 

這段代碼的輸出將是一樣的前面的例子:

about to change a, brother! 
a set to -7 
a is changed 

下面是你的榜樣情況下實現:

MyObject = { 
    __privates = { 
     a = 5, 
    } 
    __private_callback = function(self, k, ov, v) 
     if k == "a" and v == "100" then 
      print("a is 100!") 
     end 
    end 
} 
MyObject_meta = { 
    __index = function(self, k) 
     return rawget(self, "__privates")[k] 
    end, 
    __newindex = function(self, k, v) 
     local privates = rawget(self, "__privates") 
     local ov = privates[k] 
     privates[k] = v 
     rawget(self, "__private_callback")(self, k, ov, v) 
    end, 
} 
setmetatable(MyObject, MyObject_meta) 

function SomeFunctionThatOperatesSomeTime() 
    MyObject.a = -7 -- prints nothing 
    MyObject.a = 100 -- prints "a is 100!" 
    MyObject.a = 22 -- prints nothing 
end 

爲什麼是變量__privates__private_callback前綴有兩個下劃線?約定以私有成員爲前綴,在典型編程情況下不應使用兩個下劃線進行訪問。如果您熟悉面向對象的方法,並且在Java和C++等語言中實現它,您將會了解它與privateprotected關鍵字的相似之處。

如果你熟悉C#語言,你可能會看到set_a/get_a和元表如何實現類似於存取(set/get)。

+1

一個偉大的,超豐富的答案。謝謝! – Hossein

+0

很好的回答。這正是我認爲會發現有關metatables。 – luacoder

+2

樂意提供幫助。只要小心一下你觸摸了哪個「__privates」......你不知道你會發現什麼。 – Deco