-
Автор темы
- #1
Вступление
Всем привет! Это вводная часть серии статей в которых рассказывается о простых вещах, которые бывает сложно понять еще более простым языком. Данная часть полностью посвящена таблицам, и их мета друзьям, и их использовании в ваших скриптах, или API в вашем приложении/чите.От таблиц до метамодов
ТаблицыКак вы можете знать в Lua почти всё связано таблицами, они по своей природе довольно простые, и представляют из себя массив ключ → значение ( Пример в С++: std::map ). Ключом может выступать абсолютно любой объект в Lua, кроме nil, а значением могут выступать абсолютно любые типы ( и даже таблицы ).
Пример использования:
code_language.lua:
-- Можно установить ключи и значения на этапе инициализации
local someTable = { key= "value", key2="another_value" }
-- Или после создания таблицы
-- Перезаписываем оригинальное значение
someTable.key = "not_orig_value"
-- Вы также можете итерировать ключи и значения в таблицах
for key, value in pairs(someTable) do
-- Выводит все ключи и их значения
print(key .. " = " .. value)
end
Экспериментируя над таблицами в один момент вам захочется большего, и даже для этого придумали решение - это мета-таблицы! Мета-таблицы хранят пользовательские методы для контроля поведения таблиц, и при связывании с таблицей контролируют её поведение.
Например вы можете показать коллеге на наглядном примере кто он, из-за того что он выбрал JavaScript вместо Lua
Пример подобного в Lua:
code_language.lua:
-- Определяем мета-таблицу
local someMetaTable = {}
-- Переопределяем её стандартный метод __index
function someMetaTable.__index(t, key)
-- Печатаем при попытке обращения к нашей таблице для получения значения
print("Accessing key " .. key)
-- Если ключ равен "Alexander", то возвращаем строку "gay"
if key == "Alexander" then
return "gay"
end
-- В ином случае возвращаем оригинальное значение для ключа
return t[key]
end
local someTable = {}
-- Связываем нашу таблицу с мета-таблицей
setmetatable(someTable, someMetaTable)
-- Проверяем на правильность нашего кода
print(someTable.Alexander)
Вот их список:
- __index: Как было видно выше этот метамод вызывается, когда скрипт пытается получить доступ по ключу в таблице, но такого ключа не было найдено.
- __newindex. Этот метамод вызывается когда пытается присвоить значение ключу в таблице, но ключ также не был найден.
- __len: Метамод, который вызывается когда скрипт пытается получить длину через #
- __pairs: Данный метамод вызывается когда Lua выполняет итерацию по таблице с помощью функции pairs()
- __ipairs: Аналог pairs, но вместо pairs() → ipairs()
- __tostring: Метамод, который вызывается когда скрипт пытается преобразовать таблицу в строку с помощью tostring()
Конечно это сделать достаточно легко, но любой контроль имеет негативные последствия, и этот не стаёт исключением, вы теряете производительность, из-за прохождение двух мета-таблиц.
Код:
code_language.lua:
local someMetaTable = {}
local myTable = {someKey = "someValue"}
function someMetaTable.__index(t, key)
-- Пытаемся найти значение в таблице не вызывая __index
local value = rawget(t,key)
if value == nil then
-- Получаем оригинальную мета таблицу
local originalMetaTable = getmetatable(t)
if originalMetaTable ~= nil and originalMetaTable.__index ~= nil then
return originalMetaTable.__index(t,key)
end
-- Возвращаем значение, независимо от того, было ли оно найдено в таблице или в оригинальной метатаблице
return value
end
-- Устанавливаем мета таблицу
setmetatable(myTable, someMetaTable)
-- Заставляем все обращения к ключам проходить через метаметод __index
setmetatable(myTable, myTable)
Использование в С++
Таблицы Всё достаточно просто, привожу вам пример создания таблицы с комментариями:
C++:
int main()
{
// Создаем новый луа стейт
lua_State* pLuaState = luaL_newstate();
// Создаём новую таблицу в стеке
lua_newtable(pLuaState);
// Пушим ключ в стек
lua_pushstring(pLuaState, "Enq");
// Пушим значение в стек
lua_pushstring(pLuaState, "Where is the design?")
-- Устанавливаем пару в таблицу
lua_settable(pLuaState,-3)
lua_close(pLuaState);
}
C++:
int SomeTableIndex( lua_State* pLuaState)
{
// Получаем ключ
const char* szKey = lua_tostring(pLuaState, -1);
// Сравниваем ключ с "Alexander"
if( strstr(szKey, "Alexander" )
{
// Пушим значение
lua_pushstring(pLuaState, "Gay");
return 1;
}
// В ином случае возвращаем 300
lua_pushinteger(pLuaState, 300);
return 1;
}
int main()
{
// Создаем новый луа стейт
lua_State* pLuaState = luaL_newstate();
// Создаём новую таблицу в стеке
lua_newtable(pLuaState);
// Cоздаём вторую таблицу, чтобы использовать её как мета-таблицу
lua_newtable(pLuaState);
// Устанавливаем __index нашей функцией
lua_pushstring(pLuaState, SomeTableIndex);
lua_settable(pLuaState, -3);
// Связываем мета-таблицу с нашей таблицей
lua_setmetatable(pLuaState,-2);
}
Заключение
В данном материале я попытался максимально коротко, и в тоже время понятным языком объяснить таблицы и мета-таблицы, надеюсь для вас это было полезно. Спасибо!
P.S: Возможно вас может заинтересовать канал, где можно узнать о выходе подобного заранее -
Пожалуйста, авторизуйтесь для просмотра ссылки.