Lua:何时可以使用冒号语法?

虽然我理解了.:之间的基本区别,但我还没有完全弄清楚Lua允许何时使用冒号语法。例如,这样的东西确实有效:

s = "test"
-- type(s) is string.
-- so I can write a colon function for that type
function string:myFunc()
  return #self
end

-- and colon function calls are possible
s:myFunc()

然而,相同的模式似乎对其他类型无效。例如,当我有一个“table”而不是一个“string”时:

t = {}
-- type(t) is table.
-- so I can write a colon function for that type
function table:myFunc()
  return #self
end

-- Surprisingly, a colon function call is not not possible!
t:myFunc() -- error: attempt to call method 'myFunc' (a nil value)
-- But the verbose dot call works
table.myFunc(t)

继续另一个类型:

x = 1
-- type(x) is number.
-- So I was expecting that I can write a colon function
-- for that type as well. However, in this case even this
-- fails:
function number:myFunc()
  return self
end
-- error: attempt to index global 'number' (a nil value)

我正在努力理解这一点。是否正确推断出

  • 某些类型(例如“string”)允许冒号函数定义和冒号函数调用。
  • 其他类型(例如“table”)仅允许冒号函数定义,而不允许冒号函数调用。
  • 另一些类型(例如“number”)两者都不允许。

这些差异的确切原因是什么?是否有所有类型的列表,展示它们支持哪种类型的冒号语法?对于“number”情况,是否有解决方法,例如允许编写“x:abs()”?

点赞
用户1009479
用户1009479

第一个关于string的示例可以工作,因为所有的字符串共享同一个元表,并且它存储在名为string的表中。

来自string

字符串库可以在表string中提供所有函数。它还为字符串设置了元表,其中__index字段指向string表。因此,可以以面向对象的风格使用字符串函数。例如,string.byte(s,i)可以写成s:byte(i)


第二个关于table的示例无法工作,因为每个表都有自己的元表,名为table的表只是Table库中所有函数的集合。


像数字这样的类型默认不支持元表。

2015-10-10 09:19:45
用户2226988
用户2226988

补充回答:

首先需要注意,函数是一个值(也称为“一级公民”)。

在 Lua 中,: 是三个索引运算符之一。索引运算符返回一个可被索引的对象(无论是函数还是其他类型)中的“字段”的值。

索引运算符按通用性顺序排列如下:

  1. 表达式 [ 表达式2 ]
  2. 表达式 . 标识符
  3. 表达式 : 标识符 参数列表

后两者只是“语法糖”,可以重写成它们上方任何一种形式。

如果“expression2”总是一个有效的 Lua 标识符字符串,你想硬编码它,那么你会使用第二个。

如果通过“expression”对“identifier”进行索引返回的值总是一个函数,那么你会使用第三个,而且要用“expression”返回的值作为隐含的第一个参数来调用这个函数。这样的函数调用被称为“方法调用”。

此外,需要注意的是,语言/编译器不知道“字段”值是不是函数(如果你试图调用不是函数的值,你会在运行时得到一个错误)。它也不知道函数是不是一个方法(如果你没有传递适当的参数,函数可能不会按你预期的行为)。

现在,表达式值的类型必须是可索引的任何类型。请注意,表达式在编译时没有类型,因此如果表达式值的类型不能被索引,则会产生运行时错误。可索引的类型为:表格和具有 __index 元方法的任何对象。其他答案提供了详细信息。

2015-10-10 23:26:36