Knit服务与模块间传递函数时签名异常的原因排查
Lua方法调用参数错位异常的根本原因分析
问题背景
通过事件调用SCP867Service的Test方法,该方法调用Effect.Apply并传入self.PrintSomething、player、10、1、"Test"参数。在Effect模块的Apply方法中,调试显示参数均正确(player为传入的人形对象,duration为10,tickSpeed为1),但创建协程执行func(即PrintSomething)时,出现参数错位:PrintSomething中的player变为10,duration变为1,tickSpeed为nil。用户通过在调用func时额外传入nil作为第一个参数临时解决问题,现明确该异常的根本原因。
相关代码
Service脚本
--Service script function SCP867Service:Test(player) Effect.Apply(self.PrintSomething, player, 10, 1, "Test") wait(5) Effect.Remove(self.PrintSomething, player, "Test") end
Module脚本(Effect模块)
--Module script function effect.Apply(func, player, duration, tickSpeed, tag) --Check if the player already has the effect, bad code we don't check nil cases local owningPlayer = game.Players:GetPlayerFromCharacter(player.Parent) if effectsStorage[owningPlayer] and not Macros.findValue(effectsStorage[owningPlayer], func) then --Adding to all tables local functionCoroutine = coroutine.create(function()func(player, duration, tickSpeed)end)
PrintSomething方法
function SCP867Service:PrintSomething(player, duration, tickSpeed) for i = 1, duration, 1 do print("Testing count: ", i) task.wait(tickSpeed) end end
临时修复代码
local functionCoroutine = coroutine.create(function() func(nil, player, duration, tickSpeed)end)
根本原因分析
核心问题出在Lua中冒号定义方法与点号调用函数的绑定差异:
- 用冒号
:定义的方法(如SCP867Service:PrintSomething)是语法糖,会自动将调用者作为第一个参数(通常命名为self)传入方法。 - 但你在
Effect.Apply中传递的是self.PrintSomething(通过点号获取的函数引用),此时这个函数脱离了原本的SCP867Service实例绑定。当直接调用func(player, duration, tickSpeed)时,Lua会把第一个传入的player当作该方法的隐式self参数,后续参数依次错位:PrintSomething定义中的第一个参数(实际是隐式self,你命名为player)被赋值为传入的人形对象player- 第二个参数
player被赋值为duration(10) - 第三个参数
duration被赋值为tickSpeed(1) - 第四个参数
tickSpeed无对应传入值,因此为nil
临时修复中传入nil作为第一个参数,相当于手动填补了原本由冒号调用自动传入的self位置,后续参数就能与方法定义一一匹配,从而解决了错位问题。
内容的提问来源于stack exchange,提问作者gameking000
相关产品推荐
相关产品推荐

