Malandrinus 615 Опубликовано 11 Июля 2012 Кактус_523, а, так ты хочешь, чтобы тебе одному известно как заданную строку за тебя кто-то автоматом распарсил? =) Нет, парсить таки придётся. А дальше, чтобы получить нужное время, используй os.time, которая выдаёт не "количество секунд", как ты выше заявил, а "число, смысл которого зависит от платформы". Если это винда, то это и в самом деле количество секунд с какого-то там года, возможно уже прямо то число, которое тебе надо. Однако в общем случае для вычисления числа секунд с нужного момента надо использовать os.difftime(t2, t1). Где t1,t2 - это времена, которые можно собрать из компонент (год, месяц и т.д.) функцией os.time. Ещё раз, аргументы difftime - это число во внутреннем формате Lua, а результат - строго секунды. Может в стандарте есть чего... Откуда такие сомнения? Одна страница текста всего. Справочное руководство по языку Lua - Функции операционной системы P.S.: Кстати, проверил, что именно выдаёт os.time() (т.е. текущее время без аргументов). В самом деле у меня (под виндой) выдаёт время в секундах от момента начала 1970 г. - 5 часов, что очевидно соответствует моему часовому поясу. Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Поделиться этим сообщением Ссылка на сообщение
Malandrinus 615 Опубликовано 10 Сентября 2012 ColR_iT, как выделяется память под таблицы? Это зависит от того, какая часть таблицы используется. Если массив (т.е. непрерывные ключи от единицы), то в хипе выделяется память под линейный массив элементов и запоминается его размер. Если набор ключей произвольный, то естественно в том же хипе выделяется память под массив пар ключ-значение и тоже запоминается его размер. Одновременно могут присутствовать обе части. Например для строки - это равно количество символов в строке плюс один байт. Это не так. Строки в Lua не содержат символа-терминатора, а вместо этого запоминается их длина. Строки даже могут содержать символ с нулевым кодом. 2 Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Поделиться этим сообщением Ссылка на сообщение
Malandrinus 615 Опубликовано 17 Сентября 2012 Shoker А в Lua случаем нету возможности неявно передать в функцию название скрипта, откуда она была вызвана? Вопрос задан неоднозначно. Из скрипта ничего не вызывается, вызывается из функции. Поэтому непонятно, что такое "скрипт, откуда вызвана функция". Ты имеешь в виду файл, где находится функция, или имеешь в виду именно функцию, откуда вызвана текущая? Если нужен файл, содержащий данную функцию, то в сталкере имеется функция script_name(), которая возвращает имя текущего файла без расширения. Если же нужно имя вызвавшей функции, то это в общем случае может быть не выполнимо, поскольку у функции может и не быть имени вообще, как например в случае, если вызов был прямо из движка, или функция была определена только своим телом без имени или вообще была скомпилена на лету с использованием loadstring. Если уж совсем надо, то нужны отладочные возможности из debug, как советовал Artos. Однако использовать отладочные возможности в неотладочных целях - порочная практика: ненадёжно, ресурсоёмко, делает код малопереносимым и малопонятным. Типичный пример индусского подхода. Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Поделиться этим сообщением Ссылка на сообщение
Malandrinus 615 Опубликовано 18 Сентября 2012 (изменено) Shredder, Есть ли в Lua возможность пропустить шаг в цикле? В версии 5.2 добавили goto, который решает эту задачу. Ну а в сталкере придётся извращаться. К примеру так (не претендую на оптимальность, просто как вариант): for i = 1,7 do (function() -- ... if i == 3 then return end -- ... end)() end Данный вариант более-менее имитирует семантику continue в том смысле, что так можно сделать проверку на выход именно внутри, в точке выхода. Присутствуют накладные расходы на вызов функции (только вызов, компиляция происходит один раз), что в зависимости от ситуации может и не быть критично. Изменено 18 Сентября 2012 пользователем malandrinus Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Поделиться этим сообщением Ссылка на сообщение
Malandrinus 615 Опубликовано 20 Сентября 2012 Artos, мне не кажется. Топик про Lua, а значит про все его аспекты: частные и общие, устаревшие, текущие и будущие. Кроме того, нестандартные аспекты языка, присутствующие в игре, также вписываются в этот топик, поскольку в конце-концов мы на форуме модостроителей. И вообще, не надо забывать, что существует такая штука, как смежные темы, имеющие отношение сразу к нескольким областям. Задача куратора - не гонять ссаными тряпками людей, задающих вопросы по смежным темам, а спокойно направлять в нужную тему в том случае, если "смежность" переходит в "совсем не в тему". Как подразумеваемый куратор этого топика я пока никакого криминала не видел. 3 Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Поделиться этим сообщением Ссылка на сообщение
Malandrinus 615 Опубликовано 21 Сентября 2012 Artos, Мои слова не были оправданием ни в каком смысле, а были именно разъяснением моей позиции. Для определённости. Именно моей, очевидно, что это не моё дело - лезть с советами к другим кураторам. В этом смысле я конечно высказался совершенно зря. По поводу языка. Матом я не ругался и правил не нарушал, а быть образцом во всех отношениях - не моя забота. По поводу lua_help. Разумеется это не скрипт, с этим я не спорил. Два пункта были "неполная" и "устаревшая". Там же я уточнял, что полная лишь в том смысле, что всё перечислено. И почему же устаревшая? Отладочный предрелизный билд в скриптовой части практически ничем не отличается от релиза. Пара отличий имеется, но настолько неважных, что ими можно пренебречь. 1 Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Поделиться этим сообщением Ссылка на сообщение
Malandrinus 615 Опубликовано 24 Сентября 2012 Dennis_Chikin, Чтобы ответить на первый вопрос нужно знать, что именно ты хочешь этим искать. Что касается второго вопроса string.gfind( s, "[%w]*] ) и string.gfind( s, "[%w]+] ) Как оно должно работать ? для начала, функция string.gfind (или string.gmatch в новых редакциях Lua) возвращает итератор. Это значит, что пользоваться надо так: s = "строка в которой ищем" for s1 in string.gmatch(s, "шаблон") do -- что-то делаем с очередным вхождением end Что же касается смысла приведённых шаблонов. Первое, заключать %w в квадратные скобки здесь смысла нет. %w - это уже символьный класс "цифры и символы алфавита". Квадратные скобки - это формирование другого символьного класса, который в данном случае только и состоит из %w. Второе. Символ "*" (звёздочка) означает "предыдущий символ в количестве от нуля и больше". В данном случае это будет означать "непрерывная комбинация из цифр и букв длиной от нуля и больше". Момент "длиной от нуля" делает этот шаблон в таком варианте весьма бессмысленным. Поясню на примере. В строке "_1___ab12_" этим шаблоном будут найдены такие вхождения: '', '1', '', '','','ab12', '', ''. Т.е. находятся также пустые строки нулевой длины, очевидно промежутки между символами. Проблема здесь в том, что здесь этот шаблон стоит сам по себе. Обычно его используют в комбинации с другими. Последний же вариант "%w+" вполне осмысленный. Означает "любая непрерывная последовательность цифр и букв произвольной длины". Вот такой код: s = "_1___ab12_" for s1 in string.gmatch(s, "%w+") do print(s1) end выдаст такие найденные значения: '1', 'ab12'. Т.е. это удобный способ выделять идентификаторы из списков. К примеру, если я имею список имён, разделённых неважно чем - запятыми, точками с запятыми, пробелами, вертикальной чертой и т.п., то я могу их так выделить. Возможно, потребуется включить в символьный класс недостающие символы, допустимые в идентификаторах. К примеру: s = "a_1, ab12 , qqq_123" for s1 in string.gmatch(s, "[%w_]+") do print(s1) end выделит из строки идентификаторы: 'a_1', 'ab12', 'qqq_123' 2 Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Поделиться этим сообщением Ссылка на сообщение
Malandrinus 615 Опубликовано 24 Сентября 2012 Dennis_Chikin, По первому вопросу я хочу 4 числа без мусора из строки типа " -195.01,-5.12, 146.45, 50чего-то там ". Тогда примерно как ты делаешь, так и надо делать. Только пара моментов. Вот кусок шаблона, выделяющий одно число "(%-?[%-%d%.]*)". Для начала, не могу согласиться с "*" в конце. Число же есть по-любому, как может быть число включений 0? Здесь должен быть "+" (как минимум одна цифра). Дальше, зачем включать в символьный класс ещё и знак минуса "%-"? Имелся в виду вариант записи с экспонентой типа 123.45e-6 ? Но символ "e" ведь не включён, так что это не сработает. Вообще же с возможностями Lua точно формат числа не описать. Как минимум не хватает вариативной записи, также нет подвыражений. Здесь бы нормальные регулярные выражения, там можно было бы описать точно. Ну а здесь придётся частично полагаться на добросовестность тех, кто поставляет сюда исходную строку. Для случая с просто %w смысла особого нет, но поведение всей конструкции от этого изменяться же не должно по сравнению со, скажем %w_ или %w%s ? Или должно ? Я говорил о другом. Вот к примеру в таком выражении "%-?[%d%.]+" есть правая часть, которая должна быть обязательна, а знак минуса может быть или не быть. В итоге весь шаблон даёт выражение, которое не может быть пустым. Минус слева есть или нет, но это не делает выражение пустым. Если же написать что-то такое "[%w%s]*", то в этом случае не важно, что там в символьном классе. Знак "*" по-любому делает возможным нахождение пустой строки в произвольном месте. Я кстати не уверен, что Lua это обрабатывает корректно. В любом случае, это же бессмысленный результат. ColR_iT, есть и другой способ вернуть из строки - числа. a, b, c, d = loadstring("return "..str)() Мне кажется, так не стоит делать. Это неочевидное решение, формат принимаемой строки сильно ограничен синтаксисом языка, наконец, расходы на компиляцию могут многократно превысить обработку строки шаблонами. Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Поделиться этим сообщением Ссылка на сообщение
Malandrinus 615 Опубликовано 24 Сентября 2012 (изменено) Artos, В этом шаблоне "(%-?[%-%d%.]*)" два минуса. Один в начале и задаёт знак числа. Тут возражений нет. Но есть и второй минус внутри квадратных скобок. Благодаря этому минусу будет неправильно распознан и такой вариант "1-2-3-4". При этом, экспоненциальная форма всё равно не распознается, поскольку символ "E" в шаблон не включён. Также неправильно распознАется вот такой вариант "1.2.3.4..5". Хотя, если подумать, то можно на это не заморачиваться. Достаточно выделить абы как части между разделителями. Дальнейшую проверку с полной достоверностью выполнит операция tonumber. Надо только не забыть проверить возвращаемое значение на nil и адекватно отреагировать. Вот нашёл свою функцию для разделения строки, разделённой запятыми на части. function split_comma_separated_list(s) local res = {} for v in string.gmatch(s, "[^,]+") do table.insert(res, v) end return res end Дальше можно наваять что-то такое для перевода в числа: function strings2numbers(ts) local tn = {} for i,s in ipairs(ts) do local n = tonumber(s) ASSERT(n, "strings2numbers: cannot convert item '%d:%s' to number", i, v) table.insert(tn, n) end return tn end И пользоваться примерно так: local a, b, c = unpack(strings2numbers(split_comma_separated_list(s))) У меня примерно так и сделано. Много где используется. Изменено 24 Сентября 2012 пользователем malandrinus 1 Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Поделиться этим сообщением Ссылка на сообщение
Malandrinus 615 Опубликовано 9 Ноября 2012 Viнt@rь, Скорее всего не выйдет. В Lua нет постфиксных операторов и добавить их не получится, без влезания в код компилятора. Ко всему прочему, комбинация "--" является началом комментария. 1 Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Поделиться этим сообщением Ссылка на сообщение
Malandrinus 615 Опубликовано 29 Ноября 2012 Callisto, здесь по английски http://www.lua.org/m...nual.html#5.4.1 в русском разделе сайта Lua почему-то остуствует информация о шаблонах, но в сети имеется. К примеру здесь http://luagml.ucoz.ru/doc/lua/c5.html Задача разделения такой строки может быть решена к примеру так: s = "12:34" local a,b = string.match(s, "(%d+)%d+)") print(a, В строке шаблона: "%d" - символьный класс, любая цифра "+" - предыдущий символ 1 и более раза (соответственно, 1 и более непрерывно идущих цифр) "()" - включение для поиска ":" - просто символ двоеточия Идея с шаблонами в Lua - это примерно тоже самое, что регулярные выражения. Во многом даже синтаксис совпадает, но только упрощён сильно. Можно почитать про регулярные выражения (много где описано), чтобы понять общую идею, потом сравнить с Lua и просто понять, что от них можно там использовать. 1 Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Поделиться этим сообщением Ссылка на сообщение
Malandrinus 615 Опубликовано 3 Декабря 2012 Dennis_Chikin, цикл until - это выполнение до тех пор, пока условие не станет истинным. until в переводе - это "до" или "пока не". Эх молодежь, Паскаль уже никто и не помнит =) Вообще модуль погоды у меня вызывает содрогание. Но если в оригинале он ещё был хоть мало-мальски вменяемый, то в Атмосфире его искорёжили совершенно непередаваемым образом. Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Поделиться этим сообщением Ссылка на сообщение
Malandrinus 615 Опубликовано 4 Декабря 2012 Kirgudu, там всё правильно. Второй случай - это когда интервал содержит переход через границу суток, когда нижняя граница диапазона численно больше верхней. Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Поделиться этим сообщением Ссылка на сообщение
Malandrinus 615 Опубликовано 7 Декабря 2012 Dennis_Chikin, погодку по-хорошему надо делать или полудинамической (переход ночью между однотипными конфигами вместо той жуткой простыни почасовой (и половина - криво), или динамической совсем (генерить вообще все). Динамической погоду не сделать. Движковый погодный цикл же фиксированный - просто набор временных точек и погодных параметров в этих точках. Это прописано в конфигах и в течении игры не изменить. Можно по-идее делать плавные переходы между двумя разными циклами, но во-первых, я не уверен, что это нормально в движке работает. Во-вторых, это переходное состояние вроде как не сохраняется. т.е. сохранился с одной погодой, а загрузился - будет та, к которой шёл переход. Вроде так, хотя и не скажу с уверенностью. В этом смысле система погоды в Атмосфире не так уж и плоха. Ну надо определить промежуточные переходы между временными фреймами отдельных погодных циклов, но это само по себе не плохо. Когда всё это работает, то допускает весьма большое разнообразие погоды и немалую гибкость. Есть однако пара скверных моментов в той реализации, что я видел: 1. Переусложнённые, неочевидные и избыточные конфиги. Можно сделать лаконичнее, более понятно и управляемо. 2. Совершенно мутная скриптовая система. Не буду описывать в деталях. Скажу только, что добиться с этой системой требуемой частоты появления конкретной погоды почти невозможно. 1 Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Поделиться этим сообщением Ссылка на сообщение
Malandrinus 615 Опубликовано 8 Декабря 2012 Есть один нюанс языка, которому мало кто уделяет внимание. В Lua, как в языке с сильным акцентом на использование ссылок, надо делать различие между понятиями "ссылка" и "значение". Переменная в Lua - это ссылка на значение. У ссылки как таковой нет типа, тип есть только у значения, на которое эта ссылка ссылается. Типы всем известны: число, строка, таблица, userdata, логическое значение и nil. Я обращаю внимание, что nil - это всего лишь одно из возможных значений, на которое может ссылаться переменная. Далее станет ясно, почему это важно. Имена даются ссылкам, индексированная позиция в массиве или ключ в ассоциированной таблице - это тоже ссылки. Если кто не знает, то обычные именованные переменные - это на самом деле тоже значения из специальных таблиц - отражающих область видимости. Это не так очевидно, но ссылки, вообще говоря, ведут себя так-же, как обычные стековые переменные, скажем, в СИ или в любом другом традиционном языке. Теперь что со сборкой мусора. Сборщиком мусора собираются значения, на которые больше нет ссылок. Возьмём обычную переменную внутри функции. function f() local a = "str" end Здесь вроде бы всё понятно, есть локальная переменная с именем "a" со значением "str". Мы говорим, что по выходу из функции переменная вышла за область существования и была удалена сборщиком мусора. При этом обычно не делается акцента на разделении "ссылка/значение". Однако, если рассматривать эту ситуацию более пристально, то происходит следующее. - По выходе из функции удаляется стек функции - Соответственно удаляется находящаяся в стеке ссылка с именем a - Это приводит к тому, что на значение "str" больше нет ссылок - Что в свою очередь приводит к тому, что это значение, где-то там находящееся, будет удалено сборщиком мусора. Чтобы иллюстрировать этот механизм, рассмотрим иную ситуацию. function f() local a = "str" a = nil a = 1 a = nil end Здесь мы: - завели локальную переменную (ссылку) с именем "a". - сразу присвоили ей значение "str" - затем присвоили её значение nil, что привело к тому, что на значение "str" ссылок больше нет и оно будет убрано сборщиком мусора когда-то. Но ссылка осталась! - и далее мы присваиваем этой-же ссылке другое значение, другого типа (на этот раз "number") - и затем опять присваиваем всё той-же ссылке значение nil, что приводит к тому, что на значение 1 ссылок больше нет, и оно будет убрано сборщиком мусора. - при выходе из функции ссылка "a" будет удалена, но, повторюсь, не сборщиком мусора, а вместе со стеком функции. Справедливости ради надо заметить, что значения типа "nil", "number" и "boolean" имеют фиксированный и малый размер, и поэтому хранятся прямо в ссылке, а не в динамической памяти. По этой причине их не требуется удалять сборщиком мусора, поскольку их удаление по сути осуществляется в ходе замены значения ссылки другим значением. Это всего-лишь оптимизация и на общей идее никак не сказывается. Вот ещё одна ситуация, где идея ссылка/значение становится более важной и заметной: a = "str" function f() local a for ... do a = 1 end print(a) end print(a) - имеется глобальная ссылка с именем "a", которая ссылается на строковое значение "str" - мы создали локальную переменную (ссылку, помните?) в стеке функции. Вопреки расхожему мнению, это не неинициализированная ссылка! Согласно правилам Lua она имеет значение nil. - в последующем блоке мы обращаемся к ссылке "a", но к какой именно? Вот здесь важно, что ранее мы создали ссылку с тем-же именем "a" внутри функции. Поскольку эта ссылка существует и имеет область видимости "ближе", нежели глобальная ссылка с тем же именем снаружи функции, то именно они и будет использована. - таким образом, именно локальная ссылка будет ссылаться на численное значение "1" - по выходе из функции локальная ссылка будет удалена вместе со значением "1", а глобальная останется и сохранит своё значение "str". Теперь, какое это всё отношение имеет к таблицам. В таблицах хранятся именно ссылки, а не значения. Поэтому, есть в общем разница между действием "удалить элемент таблицы" и "записать nil в элемент таблицы". Разница эта проявляется не всегда. Чтобы понять когда именно, надо к сожалению знать детали реализации языка. Таблицы имеют две части: часть "ассоциативный массив", т.е. с индексами общего вида, и часть "массив", т.е. "с целыми индексами, идущими без разрывов от единицы". Для ассоциативного массива в общем разницы нет, удаляем мы ссылку или пишем в неё nil. В самом деле, при взятии значения по ключу мы получим nil, как в том случае если мы ранее записали по этому ключу nil, так и в том, если такого ключа там никогда не было. Если подумать, то если даже ссылка там остаётся, то мы именно такой результат и получим - nil в любом случае. При переборе же циклом любого вида очевидно алгоритм попросту игнорирует ссылки со значением nil. Признаться, я не помню уже детали реализации, т.е. упаковывается ли там массив после записи nil по ключу или нет, но это и не важно. Вы всё равно нельзя стандартными средствами языка узнать реальный размер этой части таблицы. А вот где становится важно понятие о ссылках и значениях так это для части массива. Дело в том, что записывая nil по индексу массива мы делаем именно это, записываем в имеющуюся ссылку другое значение (а именно nil. Помните? Это всего лишь одно из возможных значений.). При этом с остальными ссылками ничего не происходит, никак массив не перепаковывается, индексы остаются на своих местах. Просто по одному из индексов сидит nil. К чему это приводит? Вот здесь и начинаются танцы с бубном. Создатели языка, видимо желая упростит описание, никак не акцентировали внимание на ссылочной природе происходящего. Из-за этого в ряде случаев имеется противоречивость. К примеру возьмём такой случай: t = {12,34,56} t[2] = nil for i,v in ipairs(t) do print(i,v) end for i,v in pairs(t) do print(i,v) end for i=1,#t do print(i, t[i]) end алгоритм перебора в цикле с использованием ipairs (первый вариант) перебирает до ближайшего nil, если идти с первого индекса, т.е. выведет только 12. Алгоритм перебора, с использованием pairs (второй вариант), выведет все значения "не nil", т.е. 12 и 56. Здесь пока всё работает в соответствии с правилами языка. А вот оператор # (взятие длины) будет возвращать длину массива без учёта дырки, и значит перебор массива по индексу (третий вариант) выдаст все три значения 12, nil, 56. Т.е. что происходит, есть часть таблицы "массив". Если я пишу в эту часть значение nil по одному из индексов, то это просто означает, что я записал nil, в одну из ссылок, хранящихся в этом массиве. Саму ссылку это действие не удаляет. Это влияет на те алгоритмы, которые в своей работе учитывают значения ссылок, а именно ipairs и pairs. А вот оператор взятия длины (#) очевидно значения по ссылкам в части таблицы "массив" не читает, а просто выдаёт его длину. Теперь ещё веселее. Возьмём такую ситуацию: t = {1,2,3} t[6] = 45 t[4] = 12 t[5] = 34 t[2] = nil print(#t) Этот код выведет значение 6, а вот такой: t = {1,2,3} t[6] = 45 t[4] = 12 t[5] = 34 t[4] = nil print(#t) выведет 3 Т.е. здесь мы имеем таблицу, где непрерывно идущие от единицы индексы имеют сложную историю формирования. В данном случае часть индексов 1-3 заведомо была создана как массив, в том время как остальные были добавлены вразнобой. Таким образом, если мы делаем дырку в первой части, то опертор длины её игнорирует, а если во второй, то учитывает. Было бы логично предположить, что оператор взятия длины сначала просто берёт длину части-массива, затем перебирает все элементы начиная со следующего и до дырки, однако вот такой код: t = {1,2,3} t[6] = 45 t[4] = 12 t[5] = 34 t[5] = nil print(#t) уже выдаёт 6, что в общем оставляет одни вопросы, как именно это там внутри работает, и какая оптимизация приводит к этому результату. К сожалению, эти вопросы нельзя игнорировать полностью, только слепо упираясь в официально озвученный синтаксис языка. Вот типичный пример, который практически важен, но несёт в себе именно это противоречие. Допустим, я передаю в функцию произвольное число аргументов. Я мог бы написать обработку этого случая так: function f(...) local args = {...} for i,arg in ipairs(args) do end end К сожалению, если среди аргументов встречается nil, что вполне может получиться на практике, то цикл перебора ipairs на этом остановится, и аргументы, идущие за nil, будут опущены. Однако, используя особенность оператора # игнорировать нулевые ссылки в массиве, я могу написать так: function f(...) local args = {...} for i=1,#args do local arg = args[i] end end Это позволит перебрать все аргументы, независимо от их значения. 3 Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Поделиться этим сообщением Ссылка на сообщение
Malandrinus 615 Опубликовано 10 Декабря 2012 Callisto, это исключительно вопрос библиотек. В штатных библиотеках Lua, описанных в официальном мануале, таких возможностей вроде нет. Вообще говоря, Lua не больно силён в автономном варианте, и набор стандартных библиотек весьма беден. Подразумевается, что Lua - это всё же в основном расширение хост-программы. Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Поделиться этим сообщением Ссылка на сообщение
Malandrinus 615 Опубликовано 21 Декабря 2012 Kirgudu, в случае Lua вряд ли удастся что-то оптимизировать. Если бы это был СИ, то я бы получил случайное 16-и или 32-х разрядное число один раз, а потом читал бы из него биты. В Lua же затраты на вызов самой функции генерации случайного числа сопоставимы, а может и больше, чем собственно генерация этого числа. Так что напрягаться смысла нет. Artos, навскидку я бы сказал, что вариант с плавающей запятой должен быть дороже, чем целочисленный. Однако, измерение показывает, что вариант math.random() в самом деле несколько быстрее, чем, скажем, math.random(2). Надо смотреть реализацию. Если второй вариант основан на первом, то это логично. Хотя вообще говоря должно быть наоборот, получение числа с плавающей запятой должно быть основано на генерации (псевдо)случайного целого. 1 Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Поделиться этим сообщением Ссылка на сообщение
Malandrinus 615 Опубликовано 23 Декабря 2012 Dennis_Chikin, Я как-то мерял время на function f() return end ... function f( a1, a2, ... an ), ну и соответственно давая на вход разное количество аргументов. Задумчивость по мере увеличения количества аргументов растет очень сильно. Аналогично и с возвращаемыми. ( Вызов метода у объекта - еще дороже - в разы. Видимо, в т.ч. из-за передачи/обращения к ссылки на сам объект. ) Это вполне объяснимо, если знать, как Lua обрабатывает аргументы и возвращаемые значения. И то и другое передаётся через стек языка, а помещение и извлечение значений соответственно выполняется внутренними функциями. Плюс к этому, если вызывается метод класса, организованный через luabind, то для его вызова используется предварительный поиск метода через оператор индексирования, прописанный в метатаблице. Этот оператор представляет собой достаточно тяжеловесный код, скомпилированный на С++. Поэтому на самом деле иногда имеет смысл не делать функцию, а просто вставить несколько лишних строк кода. Чистый код Lua без вызовов (т.е. голая арифметика) будет скомпилирован с помощью LuaJIT и в общем-то будет выполняться всего в несколько раз медленнее, чем код С/С++. С другой стороны, давать это в качестве общей рекомендации я бы не рискнул. Какой-нибудь новичок воспримет это как прямое одобрение использовать копипасту в качестве основного инструмента. В итоге, на фоне копеечной выгоды имеем лютый несопровождаемый ужас вместо кода. P.S. Вот чего не понимаю, так это то, что обращение к переменным, записанное как v["id"] чуть не в разы быстрее, чем v.id. Это не так и не может быть так, поскольку то и другое - синтаксически эквивалентные конструкции. Вот тест, который подтверждает сказанное. local t = {["asd"] = 123} local N = 1000000 local t1, t2, t3 for i = 1,2 do local t = profile_timer() t:start() for k=1,N do end t:stop() if i==2 then t1 = t:time() end end for i = 1,2 do local t = profile_timer() t:start() for k=1,N do local b = t["asd"] end t:stop() if i==2 then t2 = t:time() end --log3("t=%f", t:time()) end for i = 1,2 do local t = profile_timer() t:start() for k=1,N do local b = t.asd end t:stop() if i==2 then t3 = t:time() end --log3("t=%f", t:time()) end log3("t2/t1=%f", (t2-t1)/(t3-t1)) Я здесь пытался провести как можно более точные измерения: во первых, избавиться от эффекта Jit компиляции, для чего время берётся со второго цикла, во-вторых, убрать постоянную часть и оставить только время самой операции. Если запустить этот тест несколько раз, то видно, что отношение времён практически равно единице с небольшим случайным отклонением не больше пары процентов в обе стороны. Вот где есть разница, так это между индексацией строкой и числом. Причём, если значение берётся по индексу из "массивной" части, то это примерно в пять раз быстрее индексации строкой, но если ищем по ключу в хешированной части, то это уже примерно в 10 раз медленнее, чем индексация по строке. Если первое смотрится закономерно, то второе на самом деле удивительно. Значит, массив предпочтительней таблицы с ключами-строками, но строковые ключи предпочтительней, причем однозначно, произвольных целочисленных ключей! Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Поделиться этим сообщением Ссылка на сообщение
Malandrinus 615 Опубликовано 24 Февраля 2013 Dennis_Chikin, не совсем понятно, о чём именно вопрос. Именно к такой функции бессмысленно? Или используя this? this - это ссылка на текущий модуль. Не до конца уверен, чей именно это сервис - внутренний игры или luabind, но точно не чистого Lua. Насчёт того, работает ли. У меня работает, я это даже использовал в своей реализации сохраняемых таймеров для отвязки от необходимости явно указывать имя модуля, в котором расположен код таймера. Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Поделиться этим сообщением Ссылка на сообщение
Malandrinus 615 Опубликовано 19 Марта 2013 for k, v in string.gfind( s, "(.*)" ) do t[k] = v end По-моему, это лишено смысла. Если надо получить два значения из string.gfind, то в паттерне надо указать две группы, т.е. пары скобок. Здесь же имеем одну, так что v всегда будет nil. К тому же сам шаблон внутри группы ".*" по сути означает "последовательность любых символов любой длины", так что этот цикл всегда делает одну итерацию, при первой и единственной итерации возвращая в k всю строку. Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Поделиться этим сообщением Ссылка на сообщение