作为一个全新的Lua用户,我花了一些时间才理解@Yu Hao的回答,所以我会尝试为其他初学者添加一些细节。如果有任何错误,请纠正我。
就我所知,像
x:someFunc()
这样的调用在以下情况下有效:
x
有一个元表
- 元表有一个字段
__index
- 该字段指向一个包含函数
someFunc
的表。
正如Yu Hao所指出的,字符串自动获得一个指向表的元表,例如:
th> s = 'test'
th> getmetatable(s)
{
__mod : function: 0x40c3cd30
__index :
{
upper : function: builtin#82
rep : function: builtin#79
split : function: 0x40ffe888
gfind : function: builtin#87
find : function: builtin#84
reverse : function: builtin#80
lower : function: builtin#81
len : function: 0x40af0b30
tosymbol : function: 0x40ffe8a8
myFunc : function: 0x41d82be0 -- note: this comes from our custom function string:myFunc()
dump : function: builtin#83
byte : function: builtin#76
char : function: builtin#77
gmatch : function: builtin#87
match : function: builtin#85
sub : function: builtin#78
gsub : function: builtin#88
format : function: builtin#89
}
}
因此,在这种情况下,s:myFunc()
会自动起作用。为了在table
中使用冒号语法,我们可以手动设置它的元表:
th> function enableColonForTable(t)
..> meta = {__index = table}
..> setmetatable(t, meta)
..> end
th> t = {}
th> enableColonForTable(t)
th> t:insert(1) -- works now!
另一个观察结果是,
__index
指向的表与类型名称完全相同并不重要。我们不仅可以使用
meta = {__index = table}
,还可以这样做:
th> arbitraryScope = {}
th> function arbitraryScope:test() return "something" end
th> t = {}
th> setmetatable(t, {__index = arbitraryScope})
{}
th> t:test()
something
这也是与“数字”案例的关键区别。虽然有名为“字符串”和“表格”的现有表,但没有名为“数字”的现有表。这就是为什么以前甚至定义例如“function number:abs()”也失败的原因。但我们仍然可以使其起作用。
th> number = {}
th> function number:abs() return math.abs(self) end
th> x = -123
th> debug.setmetatable(x, {__index = number})
-123
th> x:abs()
123
请注意,这里必须使用
debug.setmetatable
而不是
setmetatable
。两者之间的区别似乎在于
setmetatable
仅为给定实例设置元表,而
debug.setmetatable
则为整个类型设置元表。显然,为数字设置单独的
元表是被禁止的(而且也没有太多意义)。这意味着(与表相比),新构造的数字现在默认情况下具有给定的元表,因此以下代码可以正常工作:
th> y = -42
th> y:abs()
42
[*] 更新
正如Tom Blodget所指出的那样,如果x
本身充当命名空间,即它是一个带有方法字段someFunc
的表,则x:someFunc()
也可以工作。例如,您可以执行table:insert(1)
。但现在,命名空间(名为table
的表)将作为self
传递,您将向命名空间添加数据:
th> print(getmetatable(table)) -- note: "table" does not have a metatable
nil
th> table:insert(1) -- yet a colon syntax call works
th> table
{
prune : function: 0x4156bde0
getn : function: 0x41eb0720
maxn : function: builtin#90
remove : function: 0x41eb08c8
foreachi : function: 0x41eb05b8
sort : function: builtin#93
concat : function: builtin#92
unpack : function: builtin#16
splice : function: 0x4156bdc0
foreach : function: 0x41eb0688
1 : 1
pack : function: builtin#94
insert : function: builtin#91
}
string
是唯一允许这样做的类型吗? - bluenote10