Разработчик
			
			
				
					
				
			
		- Статус
- Оффлайн
- Регистрация
- 1 Сен 2018
- Сообщения
- 1,665
- Реакции
- 923
Вступление
Всем привет! Это вводная часть серии статей в которых рассказывается о простых вещах, которые бывает сложно понять еще более простым языком. Данная часть полностью посвящена таблицам, и их мета друзьям, и их использовании в ваших скриптах, или 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: Возможно вас может заинтересовать канал, где можно узнать о выходе подобного заранее -
	Пожалуйста, авторизуйтесь для просмотра ссылки.
 
				 
 
		