2011-11-29 130 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