簡體   English   中英

Lua事件處理程序

[英]Lua event handler

lua是否有內置的“事件處理程序”,或者它是否有可用的lib?

這就是一個例子,當“a = 100”事件發生時。

別的東西,而不是使用:

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

或者只是為它添加一個睡眠。 “雖然真的這樣做”只是一個例子,但它是一個可怕的例子。

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中提供的metatable,使這種行為對程序員透明。 例:

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和metatable實現與訪問器( set / get )類似。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM