检查lua函数是否匿名?

时间:2018-09-25 08:36:19

标签: lua

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

--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中找到相同的函数来注销它,但是当我使用这种形式时: / p>

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

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

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

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

2 个答案:

答案 0 :(得分:2)

  

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

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

如果传递的值(EventDispatcher:register()类型)也保存在其他位置,则无法检测function内部。因此,如果您确实对同一事件有多个回调,并且要注销一个特定的回调,则必须有一种方法来标识该确切的回调函数。

这意味着您应该将函数值保存在某个位置,以便稍后将其自身的值用作unregister()的标识符,或者返回在{{1}内部生成的新回调的实例ID。 }添加回调时。无论哪种方式,register()外部都需要存储一些内容以标识确切的回调。

答案 1 :(得分:1)

这种方式可以避免您的问题,但是仍然可以解决您的问题。

注册新的回调时,您可以简单地返回某种识别值,例如ID,表或函数本身。这样可以让您稍后取消注册。

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

缺点是您可能必须更改事件分发程序跟踪其已注册事件的方式,但是最坏的情况是这意味着实现一些链接列表,并且充其量只能使用Lua表来跟踪处理程序

对于检测匿名函数,这实际上是不可能的。 Lua不会将您就地定义的功能与存储在变量中的功能区分开来。最终是同一回事。

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