Перейти к контенту

Язык Lua. Общие вопросы программирования


Malandrinus

Рекомендуемые сообщения

Накопилось много вопросов по Lua в целом, буду задавать по порядку...

Как выделяется память для таблиц?

Подозреваю, что на каждый элемент таблицы, плюс если это хеш-таблица, то ещё и на ключи. Так ли это?

Поделиться этим сообщением


Ссылка на сообщение

Боюсь, что последующие вопросы не особо связаны какой-либо идеей, разве что они относятся к Lua.

А вопрос вроде бы достаточно адекватен: как выделяется память под таблицы?

Например для строки - это равно количество символов в строке плюс один байт.

Поделиться этим сообщением


Ссылка на сообщение

В целом разобрался, спасибо.

Ещё вопрос: есть ли принципиальная разница между использованием tbl[index] и tbl.index, возможно в скорости работы или ещё какие-нибудь нюансы?

Изменено пользователем ColR_iT

Поделиться этим сообщением


Ссылка на сообщение

AndreySol, это значит, что таблица new_table будет иметь следующий вид:

new_table = {
   [key1_name] = {
       ["param1"] = {}
   }
}

Изменено пользователем ColR_iT
  • Нравится 1

Поделиться этим сообщением


Ссылка на сообщение

AndreySol, скажем так - это некоторая особенность языка. Если совсем поверхностно и ты знаком хотя бы с основами ООП, то обращение к элементам таблицы через квадратные скобки - это обращение как к элементам таблицы, а через точку - как к структуре.

Если глубже - тогда тебе читать документацию по Lua.

P.S. Вот такие две записи эквивалентны:

tbl = {}
tbl["index1"] = 1
tbl.index1 = 1

Обе эти записи обозначают, что в таблицу tbl записан новый элемент равный числу 1, под индексом "index1".

Есть и другие особенности применения точки для таблиц. Например в игре, все функции что ты используешь - это по сути одна большая таблица, если быть точным, то это таблица _G. И когда ты в какой-нибудь функции пишешь что-то вроде такого:

file_name.function_name()

Это означает, что нужно из таблицы file_name найти элемент function_name, а поскольку это функция, то ты вызываешь функцию.

 

P.P.S. Буду рад любой критике.

Изменено пользователем ColR_iT
  • Нравится 2

Поделиться этим сообщением


Ссылка на сообщение

Viнt@rь, возможно я не до конца понял твою мысль, но точно можно сделать так:

tbl = {}
for i=1, 3 do
   tbl["vName_"..i] = "vName_"..i
end

Поделиться этим сообщением


Ссылка на сообщение

Shredder, конкретного оператора нет, но это можно с имитировать.

for i=1, 3 do
   if i ~= 2 then
       print (i)
   end
end

Результат понятен - пропускается цикл со значением счётчика равному двум.

Конечно, это далеко не универсальный вариант, но он работает.

Изменено пользователем ColR_iT

Поделиться этим сообщением


Ссылка на сообщение

Shredder

Дык, а table.foreach ничем не отличается от того же итератора pairs.

Для foreach передается два параметра: первый таблица, второй - функция, в функцию же автоматом передаётся два значения: ключ и значение этого ключа. И так происходит для всей таблицы, т.е. в функцию передаётся поочерёдно все ключи указанной таблицы.

Абсолютно тоже самое происходит и с конструкцией вида:

for key, value pairs(table) do
-- здесь по сути тело функции, которая передавалась вторым параметром для foreach.
end

Всё также пробегаемся по всем ключам таблицы и если ничего не вернули (отсутствует оператор break), то перебирать будем всю таблицу.

P.S. А к стати table.foreach в игре осталась? Вроде как её и table.foreachi нет с какой-то версии lua.

Сейчас глянул в 5.0 ещё были, в 5.1 уже исключили из стандартного набора. В игре какая версия используется?

 

Ещё заглянул в _G в 1.0006. Там функция foreach ещё есть. Но в любом случае - не вижу смысла её использовать...

Изменено пользователем ColR_iT

Поделиться этим сообщением


Ссылка на сообщение

Ложка дёгтя в бочку мёда...

Попытался вычислить время работы обоих итераторов в игре (ТЧ 1.0006 + X-Ray extension), вот результаты работы:

tbl = { ["a"] = 1, ["b"] = 2, ["c"] = 3, ["d"] = 4, ["e"] = 5, }
tbl2 = {}
tbl3 = {}

local timer = profile_timer()
timer:start()
for i = 1, 1000000 do
   for k,v in pairs(tbl) do
       if k~="b" then
           tbl2.k = v
       end
   end
end
timer:stop()
log1("##Time is "..timer:time()) --# 0.6806496875 sec

timer:start()
for i = 1, 1000000 do
   table.foreach (tbl, function (k,v)
           if k == "b" then return end
           tbl3.k = v
   end)
end
timer:stop()
log1("##Time is "..timer:time()) --# 1.581734375 sec

Как видно pairs выигрывает более чем в два раза. ;)

 

P.S. Поправил результаты. profile_timer считает время в микросекундах, а я делил результат на 105.

Изменено пользователем ColR_iT

Поделиться этим сообщением


Ссылка на сообщение

Эх, будет мне наукою... Как оказалось метод start() класса profile_timer не обнуляет значение, а продолжает считать.

Вот ПРАВИЛЬНЫЕ результаты эксперимента:

--#------------------------------------------------------------
tbl = { ["a"] = 1, ["b"] = 2, ["c"] = 3, ["d"] = 4, ["e"] = 5, }
tbl2 = {}
tbl3 = {}
tbl4 = {}
--#------------------------------------------------------------
local timer1 = profile_timer()
timer1:start()
for i = 1, 1000000 do
   for k,v in pairs(tbl) do
    if k~="b" then
	    tbl2.k = v
    end
   end
end
timer1:stop()
log1("##Time is "..timer1:time()) --# 0.684159375 sec
--#------------------------------------------------------------
local timer2 = profile_timer()
timer2:start()
for i = 1, 1000000 do
   table.foreach (tbl, function (k,v)
	    if k == "b" then return end
	    tbl3.k = v
    end)
end
timer2:stop()
log1("##Time is "..timer2:time()) --# 0.9012660625 sec
--#------------------------------------------------------------
local function f(k,v)
   if k == "b" then return end
   tbl4.k = v
end
local timer3 = profile_timer()
timer3:start()
for i = 1, 1000000 do
   table.foreach (tbl, f)
end
timer3:stop()
log1("##Time is "..timer3:time()) --# 0.7032258125 sec
--#------------------------------------------------------------

И как видно, в эксперименте появился третий вариант (спасибо Charsi). Результаты на лицо.

Так что Shredder - приношу свои извинения за дезинформацию.

Поделиться этим сообщением


Ссылка на сообщение

Dennis_Chikin, извиняюсь, что не совсем в тему, но по первому вопросу есть и другой способ вернуть из строки - числа.

str = " -195.01,-5.12, 146.45, 50"
a, b, c, d = loadstring("return "..str)()
print (a, b, c, d)
--# Результат числа:
-195.01 -5.12 145.45 50

Работать будет для строки, которая состоит из чисел разделённые запятыми.

Изменено пользователем ColR_iT

Поделиться этим сообщением


Ссылка на сообщение

proger_Dencheek, в самом алгоритме есть логическая ошибка. При первых пяти вызовах, будет действительно выдаваться рандомные сообщения и они будут удаляться из массива aa, а массив bb будет заполнятся, до тех пор, пока все элементы aa не перекочуют в bb. Шестой вызов будет использовать массив bb, поскольку проверка

if next(aa) then

вернёт false. А вот уже седьмой вызов будет вновь использовать массив aa, потому как на предыдущем этапе в него был помещён одни элемент из массива bb, и вышеупомянутая проверка благополучно вернёт истину. Далее действо будет ходить по кругу: восьмой вызов - массив bb, девятый - aa и т.д.

Поэтому используй алгоритм предложенный Gun12, он лишён данного недостатка. Про "бардак" совершенно не ясно, что ты имеешь ввиду...

P.S. И давай более внятные имена переменным, даже на этапе тестирования, это поможет избежать путаницы.

Изменено пользователем ColR_iT

Поделиться этим сообщением


Ссылка на сообщение

proger_Dencheek, ты только всё усложнил.

В целом ход твоих мыслей, лично я понял, но ты не учёл один момент. Вот это:

local arhiv = tbl

не создаёт копию таблицы, а присваивает ссылку на таблицу, т.е. arhiv и tbl это одна и та же таблица.

Так что не изобретай велосипед и используй алгоритм Gun12, он на 101% рабочий.

Изменено пользователем ColR_iT

Поделиться этим сообщением


Ссылка на сообщение

proger_Dencheek, как раз таки наоборот. Алгоритм Gun12, не повторяет сообщения, а алгоритм от Artos может на третий раз выдать сообщение которое уже было первым. Это очень легко просматривается в обоих случаях.

На счёт копии - да, так будет копия.

Поделиться этим сообщением


Ссылка на сообщение

Callisto, в любом маломальском пособии по Lua, есть исчерпывающая информация по табличным функциям.

table.remove (table, pos)
Первый аргумент (обязательный) - это таблица из которой происходит удаление.

Второй (необязательный) - это позиция с которой нужно удалить элемент таблицы. Если параметр не указывать, то удалит последний элемент таблицы. При удалении, индексы элементов выше, сдвигаются вниз.

Работает только с индексированными таблицами.

 

В твоём же случае нужно присваивать ключу, значение которое ты хочешь удалить, значение nil. Например:

table_1.0201 = nil
На Wiki есть неплохая статья по таблицам за авторством iDreD: >>ClicK Me<<, есть что почитать...
  • Нравится 1

Поделиться этим сообщением


Ссылка на сообщение

toxictrace, а ты уверен, что в качестве key ты передаёшь то, что нужно? Это единственная причина подобной ошибки.

Поделиться этим сообщением


Ссылка на сообщение

Real Wolf, в Lua по другому то и не выйдет. К сожалению, я не знаю механизма реализации наследования в LuaBind, но мне кажется, что от обычного Lua'шного способа с копированием таблиц и метатаблиц он не сильно отличается. LuaBind это ведь "обёртка", упрощающая написание кода или я ошибаюсь?

Поделиться этим сообщением


Ссылка на сообщение

У меня есть шесть абсолютно одинаковых функций, разные лишь названия, я их заношу в табличку и когда названия разные - никаких проблем нет. В целях уменьшения размера кода, я хочу сделать одну "общую" функцию и для шести функций передать ссылку на неё, но при занесении их в таблицу сталкиваюсь с тем, что первая функция затирается второй и т.д.

Вот пример:

function func (value)
    print (value)
end

tbl = {}

function Past(f,v)
    tbl[f]={v=v}
end

function OnPrint()
    func2 = func
    func3 = func
    Past (func2, "two")
    Past (func3, "three")
    for fun,val in pairs (tbl) do
        fun(val.v)
    end
end
При вызове функции OnPrint, естественно, в качестве результата я вижу лишь "three", т.к. func2 и func3 это ссылки на func.

Вопрос: можно ли подправить код так, чтобы в результатах отобразилась и "two" и "three" без явного вызова функции func в функциях func2 и func3?

Изменено пользователем ColR_iT

Поделиться этим сообщением


Ссылка на сообщение

@abramcumner, не очень понял о чём Вы.


@Shredder, при таком подходе не получится удалить один элемент из таблицы таким образом:

tbl[f] = nil
Т.к. удаляться они будут по отдельности, а так выйдет все скопом.
  • Нравится 1

Поделиться этим сообщением


Ссылка на сообщение

Тупанул, когда не объяснил всей сути, признаю...

Если кто знаком с файлом xr_s.script, то тому код будет знаком. :)

У меня есть в целом вот такая конструкция:

tbl = {}

function Register(f,v)
    tbl[f]={v=v}
end

function Unregister (f)
    tbl[f]=nil
end
--#---------
function update ()
    for func,param in pairs(tbl) do
        func(param.v)    
    end
end
--#---------
function func2 (value)
    print (value)
end
function func3 (value)
    print (value)
end

function Past()
    Register (func2, "two")
    Register (func3, "three")
end
Функции func2 и func3 вносятся в таблицу tbl посредством функции Register, это я делаю в нужный мне момент. Функция update периодически обновляется и тем самым апдейтит обе мои функции func2 и func3. Когда мне не нужно обновлять, например, функцию func2, я вызываю функцию Unregister(func2) и тем самым оставляю в биндящейся функции, а точнее в таблице, итерация которой находится там, лишь func3.

Со временем функции func2 и func3 разрослись (к тому же их не две, а шесть) и стали изрядно занимать место. Т.к. функции имеют одинаковое тело, то я подумал, почему бы не сократить код до одной "общей" функции, а передавать ссылку на неё шести другим (к сожалению, передачи по значению в Lua нет), но столкнулся с проблемой, которую не смог обойти, скажем так, изящнее, нежели вызывать одну общую функцию внутри этих шести, на манер такого:

function func (value)
    print(value)
end

function func2(value)
    func(value)
end
function func3(value)
    func(value)
end
Имхо, не комильфо.

А проблема со ссылкой, думаю, ясна - в таблице tbl, при использовании Register будет всегда одна и тот же ключ. От чего и попросил Вашего совета. :)

Изменено пользователем ColR_iT

Поделиться этим сообщением


Ссылка на сообщение
  • Недавно просматривали   0 пользователей

    • Ни один зарегистрированный пользователь не просматривает эту страницу.
×
×
  • Создать...