Lua: 冒号符号表示法,'self'和函数定义与调用的区别

12

我对定义/调用 Lua 函数时使用的冒号表示法感到非常困惑。

我觉得我已经理解了它,直到我看到了这段代码:

function string.PatternSafe( str )
    return ( str:gsub( ".", pattern_escape_replacements ) );
end

function string.Trim( s, char )
    if char then char = char:PatternSafe() else char = "%s" end
    return string.match( s, "^" .. char .. "*(.-)" .. char .. "*$" ) or s
end

让我困惑的是string.PatternSafe()在任何地方都没有引用'self',但是代码似乎能够正常工作。

我也看到一些脚本在定义函数时使用冒号符号,例如:

function foo:bar( param1 ) ... end

经过几个小时的谷歌搜索,我仍然无法弄清楚在这两种情况下到底发生了什么。 我目前的假设如下:

  1. 如果使用冒号符号定义一个函数,则会插入一个不可见的“self”参数作为第一个参数。
  2. 如果使用冒号符号调用函数,则在冒号之前的对象被插入到参数中(因此成为函数的第一个参数)。
  3. 如果使用点符号调用函数,则即使使用冒号符号进行定义,它也不会将对象插入为第一个参数/参数。

如果我的假设是正确的,那就引出了另一个问题:如何确保函数被正确调用?


可能是重复问题:Lua中.和:的区别 - Oleg V. Volkov
1个回答

10

你的所有假设都是正确的。

来自手册的假设1:

冒号语法用于定义方法,即具有隐含额外参数 self 的函数。因此,该语句

 function t.a.b.c:f (params) body end

是语法糖的简写形式

 t.a.b.c.f = function (self, params) body end
来自手册的假设2:
 

调用v:name(args)是对v.name(v,args)的语法糖,除了只对v进行一次求值。

假设3没有直接的手册部分,因为那只是普通的函数调用语法。
不过这里有一件事。`self`只是在使用冒号赋值作为语法糖时自动分配的名称,它不是必需的名称。第一个参数是第一个参数,无论名称是什么。
因此,在您的示例中:
function string.PatternSafe( str )
    return ( str:gsub( ".", pattern_escape_replacements ) );
end

第一个参数是str,所以当函数被调用为char:PatternSafe()时,它会被解糖(通过假设2),变成char.PatternSafe(char),这只是将char作为第一个参数传递到函数中(正如我已经说过的,第一个参数是str)。


从被调用的函数内部,如何最好地确定它是使用点号还是冒号表示法调用的?编辑:特别是,如果意外使用点表示法进行调用,则'self'将吞噬下一个参数(因此在foo:bar示例中,如果我调用foo.bar(“test”),则self参数将吞噬param1,而param1将为nil)。 - cabbageforall
1
在函数中,你无法知道如何调用它。它们并没有不同。这只是一些语法糖。但是你可以知道有多少参数以及它们的“类型”。 - Etan Reisner
@Etan 嗯,一个可能的解决方案是检查传递了多少个参数。多传了1个?使用冒号语法。 - warspyking
@warspyking,除非调用者恰好将您需要的输出产生的函数的输出传递给您,然后您不关心计算出多余的输入并且Lua会将其删除等(例如table.remove(tab, index_from_value(tab, value)),其中index_from_value为方便起见返回ind,val)。这就是为什么我曾经经常告诉人们编写C模块时不要在函数开头断言lua_gettop值的原因。但是,是的,如果您不关心,您可以通过“猜测”的方式来解决(我用“多少”暗示了这一点)。 - Etan Reisner
@Etan,实际上我用包装器完成了这个操作,当包装一个userdata时,我必须确定他们使用的是点号还是冒号语法。我必须以那种方式进行检查:P - warspyking
@warspyking 没错。你可以近似地表示它(尤其是如果你的参数类型值有帮助的话),但这只是一种启发式的方法而已。 - Etan Reisner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接