Как новичок в Lua, мне потребовалось некоторое время, чтобы понять ответ @Yu Hao, поэтому я попытаюсь добавить некоторые детали для других новичков. Пожалуйста, поправьте меня, если что-то не так.
Насколько я вижу, вызов типа x:someFunc()
работает, если [*]:
x
имеет метатаблицу
- а в метатаблице есть поле
__index
- который указывает на таблицу, содержащую функцию
someFunc
.
Как указал Ю Хао, строки автоматически получают метатаблицу, указывающую на таблицу string
, например:
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
Это также ключевое отличие от случая number
. Хотя существуют таблицы с именами string
и table
, таблицы с именем number
не существует. Вот почему даже определение, например. 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
[*] Обновление
Как указал Том Блоджет, 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
}
person
bluenote10
schedule
10.10.2015