【问题标题】:Lua: How do I execute a callback passed from a parameter?Lua:如何执行从参数传递的回调?
【发布时间】:2018-06-05 11:10:58
【问题描述】:

我在没有运气的情况下搜索了这个问题的答案。我只发现了人们将回调传递给调用者函数的例子,但还没有看到调用者实际上是如何在内部执行回调函数代码的。如果有人可以为此提供一个示例和解释,将不胜感激。

我从功能的角度了解回调是如何工作的,我已经在其他语言中使用过它们。我只是无法弄清楚如何在 lua 中正确执行此操作的语法。我要么执行错误的回调参数,要么错误地将其传递给调用者函数。

这是我正在尝试做的一些伪代码,只是一个简单的例子,所以我可以看到它的工作原理。 (我是视觉学习者)

callback = function ()
    ... do stuff ...
end

function caller(callback)
    callback()
end

-- run caller function
caller(callback)

编辑: 我得到了一些答案,说我上面的例子有效,而且看起来确实有效。谢谢你,但我想我应该更具体一些,因为尽管语法正确,但我的实际代码无法正常工作。

我正在为使用基本模式的 FiveM 服务器进行一些编码。我试图在脚本中使用回调来清理代码,但它似乎没有触发回调函数。这是sn-ps...

客户端脚本:

RegisterNetEvent("parachute:callback")
AddEventHandler('parachute:callback', function(callback)
    print("callback...")
    callback()
end)

服务器脚本:

callback = function ()
    print("callback fired")
    GiveWeaponToPed(GetPlayerPed(-1), GetHashKey("GADGET_PARACHUTE"), 150, true, true)
    SetPedComponentVariation(GetPlayerPed(-1), 5, 1, 0, 0)
end

TriggerEvent('es:addCommand', 'callback', function(source, args, user)
    TriggerClientEvent("parachute:callback", source, callback)
end, {help = "TEST"})

在上面,print("callback...") 函数执行但callback() 函数不执行。我可以根据我添加的打印语句来判断。

对于那些不熟悉基本模式或 FiveM 脚本的人来说,要获得更多上下文,这里有一个客户端加载脚本和一个服务器加载脚本。在服务器中,TriggerEvent('es:addCommand', ... ) 添加了一个可以使用/<cmd name> 执行的命令。 TriggerClientEvent() 通过RegisterNetEvent()AddEventHandler() 创建的监听器在客户端启动一个事件。如您所见,您将回调传递给这些函数,以告诉它们在触发事件时要执行什么。回调函数本身只是给我的角色一个降落伞。但是,当我输入 /callback 时没有给出降落伞。

如果不是我最初想象的语法,会出现什么问题?

【问题讨论】:

  • 只是一个刺,但你确定论点是正确的吗?你能把 args 和你的 print("callback...") 一起转储吗?也许添加一个print('callback type: '..type(callback)),如果它是一个表for k,v in pairs(callback) do print('callback["'..tostring(key).."]: '..tostring(v)) end
  • 不确定 essentialmode 是如何工作的,但看起来您正在服务器上声明一个回调函数并将其与事件一起传递给客户端,以便客户端可以调用服务器上的函数。我怀疑这会起作用,我认为它们是孤立的环境。
  • 是的,我相信这就是原因。我忽略了服务器和客户端有两个不同的地址空间的事实。如果您编辑答案以将其添加(为了完整起见),我会接受您的正确答案

标签: syntax lua callback


【解决方案1】:

函数可以是 lua 中的变量,但它们就像任何其他变量一样。

我不知道您的示例有什么问题,看来您完全正确。只需输入您的代码即可 (try it here)。

更新

FiveM 和essentialmode 似乎是客户端/服务器,并在两个不同的执行环境中运行。他们可能会为客户端和服务器之间的通信序列化数据,但传递一个函数是行不通的。

您可以使用loadstring() 做一些事情...这是您可以在 jdoodle 上运行的示例:

function sayHi(name)
  print("Hello, "..tostring(name).."!")
end

-- create string representation of the function
local functionDef = string.dump(sayHi)

-- convert back to a function
local func = loadstring(functionDef)
func('Jason')

-- or use a string directly, just body, no arguments so
-- we 'return' a function and call it with () after loadstring 
-- to get the returned function - [[ ]] is just syntax for a
-- multiline string
local func2 = loadstring([[
        return function(name) 
          print("Hi there, "..tostring(name).."!")
        end
    ]])()
func2('Jason')

String.dump 将现有函数序列化为字符串,loadstring 将其转换回函数。您可以在客户端和服务器之间传递此字符串,但它会在执行它的任何环境中执行。您也可以传递一个函数体,但要获取参数,您必须返回一个在该函数体中带有参数的函数并调用它以获取返回值以使用该函数。

如果在客户端上执行GiveWeaponToPedSetPedComponentVariation,那么您可以发送这些命令来代替“回调”参数并在客户端中使用 loadstring...

客户

RegisterNetEvent("parachute:callback")
AddEventHandler('parachute:callback', function(callback)
    print("callback...")
    loadstring(callback)()
end)

服务器

codestring = [[
    GiveWeaponToPed(GetPlayerPed(-1), GetHashKey("GADGET_PARACHUTE"), 150, true, true)
    SetPedComponentVariation(GetPlayerPed(-1), 5, 1, 0, 0)
]]

TriggerEvent('es:addCommand', 'callback', function(source, args, user)
    TriggerClientEvent("parachute:callback", source, codestring)
end, {help = "TEST"})

【讨论】:

  • 澄清一下:变量有两种,全局变量和局部变量(包括循环变量和参数,可以包括self)。而且,有几种类型的值,包括函数。说“函数可以是变量”或“全局……函数”听起来很奇怪。不过你的推理是合理的。
  • 感谢您的反馈,我已经更新了我的问题
【解决方案2】:

它将完全按照您的描述工作。你可能想在你的回调函数前面添加local,但除此之外,你应该很好。这是一个工作示例:

local callback = function ()
    print("here")
end

function caller(callback)
    callback()
end

-- run caller function
caller(callback)

【讨论】:

  • 感谢您的反馈,我已经更新了我的问题
猜你喜欢
  • 1970-01-01
  • 2018-10-11
  • 1970-01-01
  • 2016-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-14
相关资源
最近更新 更多