Кратко: это очень сложный материал, тк автор этой статьи слаб, плохо понимает, и редко применяет их. Часто не могу найти применение мета-таблицам. Мне хватает и базовых знании. Возможна будет не раз эта статья дорабатываться позже мной, и xgm-сообществом, если конечно, будет.
Мета-таблицы — это самые обыкновенные таблицы, содержащие функции, которые изменяют стандартное поведение операторов в Lua.
--для созданной таблицы mytable устанавливаем мета-таблицу mymetatable
mytable = {} --основная таблица
mymetatable = {} --мета-таблица - управляемая таблица
setmetatable(mytable,mymetatable) --для основной таблицы mytable задаем мета-таблицу mymetatable - уаправляющая таблица над которой имеет контроль mytable
аналогично выше запись можно записать и по-другому в одну строчку:
mytable = setmetatable({},{})
или
mytable = setmetatable({}, mymetatable)
metatable - это точно такая обычная таблица. Когда вы устанавливаете table для metatable setmetatable(table,metatable), table получает управление над metatable.
Если нужно узнать есть ли у teble metatable мета-таблица => есть функция getmetatable(metatable) пример кода выявления таблицы
mytable = {}
print(getmetatable(mytable)) --> печает nil, значит, у таблицы mytable никакой мета-таблицы
давайте, зададим mytable мета-таблицу
mymetatable = {}
setmetatable(mytable, mymetatable)
print(getmetatable(mytable) == mymetatable) --вернет true, что означает, что у мета-таблица совпадает
если два раза задать основной таблице две разные таблицы, то у главной таблицы запишется какая то одна из них. Т.е. новая мета-таблица перезаписывает старую, то есть управление основная таблица может получить только над одной. А другая уже перестает быть метатаблицей. если ранее была какая то другая таблица, то получаем управление над новой.
короче, в чем суть? есть табличные мета-методы. и можно ими управлять этой таблицей. там всякие операции и пр. В этом вся суть.
я думал ранее, что в главную таблицу добавляю много разных мета-таблиц. получается что это не то. это просто для удобства: для таблицы берем одну мета-таблицу, и что-то делаем: пример прибавляем к таблице данные мета-таблицы. Есть разных различных мета-методов
Мета-таблицы - те же обычные таблицы, с определёнными внутри их специальными функциями - мета-методами. Метатаблица может иметь любой тип в Lua, они позволяют переопределить поведение данных типов при выполнении операций. Для таблиц это доступно прямо в Lua, для других типов придётся использовать C API (поэтому будем рассматривать только табличные метатаблицы).
Для установки и получения метатаблиц в Lua по стандарту существует 4 функции:
Для установки и получения метатаблиц в Lua по стандарту существует 4 функции:
---@param table table
---@param metatable table
---@return table
setmetatable(table, metatable) -- это основная функция, которая позволяет установить таблице метатаблицу. Такая функция работает только с таблицами.
---@param value value
---@return table or value
getmetatable(value: value) -- возвращает метатаблицу, если есть или значение поля __metatable в метатаблице, если есть. Работает со всеми значениями.
---@param value value
---@return boolean or value
debug.setmetatable(value: value) -- устанавливает метатаблицу любому значению и обходит метаполе __metatable. Действительно мощная штука, вот почему её убрали в Open Computers .
---@param value value
---@return table or value
debug.getmetatable(value: value) -- возвращает метатаблицу, обходя поле __metatable. Также отсутствует в OC.
пример, возьмем такую функцию, где создается новая точка вектора:
при каждом обращении создают новую таблицу. создать/двигать вектор итд. тогда я думал это странно. мы же должны об утечках думать. мне объяснили, что если переменную обнулить, таблица также удаляется. аналогично думается что если ссылка теряется. то таблица тоже удаляется. необычный способ мб потом с векторами поработаем
при каждом обращении создают новую таблицу. создать/двигать вектор итд. тогда я думал это странно. мы же должны об утечках думать. мне объяснили, что если переменную обнулить, таблица также удаляется. аналогично думается что если ссылка теряется. то таблица тоже удаляется. необычный способ мб потом с векторами поработаем
vector:new = function(self, x, y, z) --self не обязательно писать. пример в vector:new(x,y,z) self ссылается на метатаблицу. типа vector.mt
local o = {}
setmetatable(o,self) --обычно setmetatable(table,metatable) задает метатаблицу для table. Тут все наоборот. метаблица для self-таблицы
o.x = x or 0.
o.y = y or 0.
o.z = z or 0.
return o
end
Если создать вектор
local vector={}
vector:new(x,y,z)
это все равно, что задать
vector.x = x
vector.y = y
vector.z = z
Теперь, я думаю, можно приступить к самим мета-методам. Для своего, а может быть и вашего удобства я их разделю на четыре категории:
__index( self, key ) чтение по ключу
__newindex( self, key, value ) запись по ключу
__call( self, ... ) вызов как функции
__add( self, arg ) сложение
__sub( self, arg ) вычитание
__mul( self, arg ) умножение
__div( self, arg ) деление
__mod( self, arg ) остаток от деления
__pow( self, arg ) возведение в степень
__unm( self ) унарный минус
__concat( self, arg ) конкатенация строк
__len( self ) длина
__eq( self, arg ) оператор "равно"
__lt( self, arg ) оператор "меньше"
__le( self, arg ) оператор "меньше или равно"
__tostring( self ) Вызывается при попытке перевести объект в строковое представление (например с помощью функции tostring)
__gc Вызывается для userdata-объектов при сборке мусора
__metatable Если задать это поле в метатаблице, то getmetatable будет просто возвращать его значение, а setmetatable вернет ошибку.