Метатаблицы и __index: ООП на Lua
Узнаём, как из обычных таблиц сделать объекты с методами и наследованием.
Метатаблица — это таблица, которая описывает «особое поведение» другой таблицы: что делать при сложении, сравнении или обращении к отсутствующему ключу.
В Lua нет классов как отдельной конструкции. Зато есть метатаблицы — механизм, на котором строят и ООП, и операторы, и многое другое. Это самая «магическая» часть языка.
Метаметод __index
Когда вы обращаетесь к отсутствующему полю таблицы, Lua заглядывает в её метатаблицу, в поле __index. Это и есть основа наследования:
local Animal = {}
Animal.__index = Animal
function Animal.new(name)
local self = setmetatable({}, Animal)
self.name = name
return self
end
function Animal:speak()
print(self.name .. " издаёт звук")
end
local cat = Animal.new("Кот")
cat:speak()Вывод:
Кот издаёт звук
Здесь setmetatable({}, Animal) связывает новый объект с таблицей Animal. Когда мы зовём cat:speak(), Lua не находит speak в cat и через __index берёт его из Animal.
Двоеточие и self
Запись function Animal:speak() с двоеточием автоматически добавляет первый скрытый параметр self — ссылку на объект. Вызов cat:speak() тоже через двоеточие передаёт cat как self.
Наследование
local Dog = setmetatable({}, {__index = Animal})
Dog.__index = Dog
function Dog.new(name)
local self = Animal.new(name)
return setmetatable(self, Dog)
end
function Dog:speak()
print(self.name .. " говорит: Гав!")
end
local rex = Dog.new("Рекс")
rex:speak()Вывод:
Рекс говорит: Гав!
Цепочка поиска
cat.speak не найдено в cat
│
└─> __index = Animal
│
└─> Animal.speak найдено!Как работает под капотом
Метатаблицы дают и другие метаметоды: __add для оператора +, __eq для ==, __tostring для красивого вывода через print. Например, задав __add, можно складывать векторы как обычные числа. Именно так в Roblox устроены типы Vector3.
Частые ошибки
- Забыть строку
Animal.__index = Animal— тогда методы не найдутся и будет ошибка проnil. - Путать
.и:при вызове методов. Метод сselfзовут через двоеточие. - Думать, что
__indexкопирует методы в объект. Он лишь указывает, где их искать.
Итог
- Метатаблица задаёт особое поведение таблицы через метаметоды.
__indexописывает, где искать отсутствующие поля — это основа наследования.setmetatableсвязывает объект с «классом»; двоеточие добавляет скрытыйself.- Другие метаметоды (
__add,__eq,__tostring) переопределяют операторы и вывод.