【问题标题】:Lua event handlerLua 事件处理程序
【发布时间】:2019-06-12 16:39:48
【问题描述】:

lua 是否有内置的“事件处理程序”或是否有可用的库来执行此操作?

例如,当“a = 100”时发生事件。

其他东西而不是使用:

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

或者只是给它添加一个睡眠。 “while true do”只是一个例子,但它是一个可怕的例子。

【问题讨论】:

  • 好吧。基本上检查一个值,如果它符合要求,就会调用一个事件。只是不要以“ifs”的方式或像上面的“while true do”那样做,因为它不合适。例如,可以随时满足要求,而不是我可以调用 if 语句的特定部分或时间。我希望这能解释一下。

标签: lua


【解决方案1】:

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

为了防止这种潜在的不良行为,可以使用 setter 函数,例如:

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) 的相似之处。

【讨论】:

  • 很好的答案。这正是我认为关于元表的结果。
  • 乐于助人。小心你碰了谁的__privates...你不知道你会抓住什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-15
  • 2018-01-25
  • 2013-12-24
  • 1970-01-01
  • 1970-01-01
  • 2011-03-22
  • 1970-01-01
相关资源
最近更新 更多