Love2D: Метатаблицы и метаметоды

Руководство по Lua 5.1
Метатаблицы - те же обычные таблицы, с определёнными внутри их специальными функциями - метаметодами. Метатаблицу может иметь любой тип в Lua, они позволяют переопределить поведение данных типов при выполнении операций. Для таблиц это доступно прямо в Lua, для других типов придётся использовать C API (поэтому будем рассматривать только табличные метатаблицы). Приведём пример для наглядности.
Можно реализовать сложение двух таблиц (в самом языке такая операция не предусмотрена):
local data1 = {x = 1} -- создаём первую таблицу
local data2 = {x = 2} -- вторую

local meta = {} -- пока что это обычная таблица
function meta.__add(op1, op2) -- в ней определяем специальное поле __add (метаметод)
    return op1.x + op2.x
end

setmetatable(data1, meta)-- устанавливаем метатаблицу первому операнду (можно и второму)

print(data1 + data2) -- проверяем
 --> 3 -- проверяем
Что мы сделали? Создали два объекта, каждый из которых содержит поле х. Создали обычную таблицу meta. В ней определили функцию со специальным именем add (тот самый метаметод. Обратите внимание, что перед именем стоит двойное нижнее подчёркивание ), затем установили метатаблицу первому операнду, использовав функцию setmetatable (table, metatable) (можно было и второму, результат остался бы тем же).
Когда Lua обнаруживает операцию над значением, то сначала ищется подходящий обработчик в метатаблице первого операнда, и если там нет, то ищется обработчик в метатаблице второго операнда. Если обработчика и там нет, то генерируется ошибка.
Также можно получить метатаблицу объекта функцией getmetatable (object)
Вот список операций, обработчики которых могут быть переопределены в метатаблице:
ОбработчикОператор LuaПримечание
__add(op1, op2) + сложение
__sub(op1, op2) - вычитание
__mul(op1, op2) * умножение
__div(op1, op2) / деление
__mod(op1, op2) % деление по модулю
__pow(op1, op2) ^ возведение в степень
__unm(op) - унарный минус
__concat(op1, op2) .. конкатенация (склейка)
__len(op) # унарный оператор взятия длины
__eq(op1, op2) == оператор "равно"
__lt(op1, op2) < оператор "меньше"
__le(op1, op2) <= оператор "меньше либо равно"
__index(op, key) [] оператор обращения по ключу. Вызовется если, например, вызвать local x = data1[1]
__newindex(op, key, value) [] оператор присвоения нового значения по ключу. Если сделать эту функцию пустой, то таблица станет "readonly", то есть в нее нельзя будет добавить новое поле со значением. Сработает если, например, вызвать data1[1] = 1
call(op, ...) () оператор вызова функции. Сработает если, вызвать data1(1, 2, 3). В обработчик call первым параметром придет операнд (в нашем случае data1), а следующими параметрами будут те параметры, что стояли в скобках (в нашем случае 1, 2, 3).

Просмотров: 2 772

Комментарии пока отсутcтвуют