【问题标题】:check if a lua function is anonymous?检查一个lua函数是否是匿名的?
【发布时间】:2018-09-25 19:21:17
【问题描述】:

我在我的游戏中将回调注册为事件处理程序,如下所示:

--register event handler
EventDispatcher:register("fire", mt.onPlayerFire, self)


--this is the event handler
mt:onPlayerFire()
    print("play fire")
end

--unregister event handler
EventDispachter:unregister("fire", mt.onPlayerFire, self)

当事件处理程序是模块mt中的一个函数时,注销它很好,因为我可以在mt中找到相同的函数来注销它,但是当我使用这种形式时:

EventDispatcher:register("fire", function() doSomething() end, nil)

我无法取消注册事件处理程序,因为它是匿名的,所以我想在我的 register 函数中添加一些检查,以防止匿名函数作为事件处理程序。

我发现 lua 源代码中的 Proto 结构可能会有所帮助,但我不知道每个部分的含义。

https://www.lua.org/source/5.3/lobject.h.html#Proto

【问题讨论】:

  • 您可以引入新功能unregister_last() 以便能够取消注册最后注册的功能而无需指定它。您注册的系统会记住register() 调用堆栈,而unregister_last() 函数将从该堆栈中“弹出”一个函数并取消注册。

标签: lua


【解决方案1】:

我无法取消注册事件处理程序,因为它是匿名的

Lua 中的每个函数都是匿名值。所以你不能取消注册不是因为它是匿名的,而是因为你没有保存对它的任何引用。

如果传递的值(function 类型)也保存在其他地方,则无法检测到 EventDispatcher:register() 的内部。因此,如果您确实对同一事件有多个回调,并且您想取消注册一个特定的回调,那么您必须有一种方法来识别确切的回调函数。

这意味着您应该将函数值保存在某处,以便以后可以将其自己的值用作unregister()的标识符,就像现在一样,或者返回新回调的实例ID,在回调时在register()内部生成添加。无论哪种方式,都需要在 EventDispatcher 之外存储一些东西来识别确切的回调。

【讨论】:

    【解决方案2】:

    这种方式避免了你的问题,但它仍然可以解决你的问题。

    注册新回调时,您可以简单地返回某种标识值,例如 ID、表格甚至函数本身。这可以让您稍后取消注册。

    local firehandler = EventDispatcher:register("fire", function() do('something') end)
    -- Do some stuff here...
    EventDispatcher:unregister(firehandler)
    

    缺点是您可能必须更改事件调度程序跟踪其注册事件的方式,但在最坏的情况下这意味着实现一些链表,而最好的情况是您可以只使用 Lua 表来跟踪您的处理程序.

    至于检测匿名函数,那是不可能的。 Lua 不会区分您就地定义的函数和存储在变量中的函数。最终都是一样的。

    可能通过使用debug 库,通过将定义函数的文件/行与调用堆栈进行比较,但这只是将错误引入您的代码,并且可能会相当慢。

    【讨论】:

    • 我使用数组来跟踪特定事件的所有事件处理程序,并返回存储处理程序的数组索引,但问题是当我取消注册前一个处理程序时,数组会向下移动其他处理程序,使先前返回的索引无效。所以我想我不应该使用数组来存储我的处理程序,还有什么建议吗?
    猜你喜欢
    • 1970-01-01
    • 2015-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-29
    • 2018-10-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多