Поиск…


Вступление

Сам Lua не предлагает систему классов. Однако возможно реализовать классы и объекты в виде таблиц с помощью нескольких трюков.

Синтаксис

  • function <class>.new() return setmetatable({}, {__index=<class>}) end

Простая ориентация объекта

Вот базовый пример того, как сделать очень простую систему классов

Class = {}
local __instance = {__index=Class} -- Metatable for instances
function Class.new()
    local instance = {}
    setmetatable(instance, __instance)
    return instance
-- equivalent to: return setmetatable({}, __instance)
end

Чтобы добавить переменные и / или методы, просто добавьте их в класс. Оба могут быть переопределены для каждого экземпляра.

Class.x = 0
Class.y = 0
Class:getPosition()
    return {self.x, self.y}
end

А для создания экземпляра класса:

object = Class.new()

или же

setmetatable(Class, {__call = Class.new}
    -- Allow the class itself to be called like a function
object = Class()

И использовать его:

object.x = 20
-- This adds the variable x to the object without changing the x of
-- the class or any other instance. Now that the object has an x, it
-- will override the x that is inherited from the class
print(object.x)
-- This prints 20 as one would expect.
print(object.y)
-- Object has no member y, therefore the metatable redirects to the
-- class table, which has y=0; therefore this prints 0
object:getPosition() -- returns {20, 0}

Изменение метаметодов объекта

имеющий

local Class = {}
Class.__meta = {__index=Class}
function Class.new() return setmetatable({}, Class.__meta)

Предполагая, что мы хотим изменить поведение одного экземпляра object = Class.new() используя метатебель,

есть несколько ошибок, которых следует избегать:

setmetatable(object, {__call = table.concat}) -- WRONG

Это заменяет старый метатебель на новый, поэтому разбивает наследование класса

getmetatable(object).__call = table.concat -- WRONG AGAIN

Имейте в виду, что таблицы «значения» являются только ссылкой; на самом деле существует только одна фактическая таблица для всех экземпляров объекта, если конструктор не определен как 1 , поэтому, делая это, мы модифицируем поведение всех экземпляров класса.


Один правильный способ сделать это:

Без изменения класса:

setmetatable(
    object,
    setmetatable(
        {__call=table.concat},
        {__index=getmetatable(object)}
    )
)

Как это работает? - Мы создаем новый метатебель, как в ошибке №1, но вместо того, чтобы оставить его пустым, мы создаем мягкую копию оригинального метатега. Можно сказать, что новый метатебель «наследует» от исходного, как если бы он был экземпляром класса. Теперь мы можем переопределять значения исходного метатета без их модификации.

Изменение класса:

1-й (рекомендуется):

local __instance_meta = {__index = Class.__meta}
-- metatable for the metatable
-- As you can see, lua can get very meta very fast
function Class.new()
    return setmetatable({}, setmetatable({}, __instance_meta))
end

2-й (менее рекомендуется): см. 1


1 function Class.new() return setmetatable({}, {__index=Class}) end



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow