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

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


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

С чего начинать и где взять.

 

Установка Lua:
http://www.amk-team.ru/forum/index.php?showtopic=11584&p=629106

 

Руководство «Программирование на языке Lua», третье издание:
http://www.amk-team.ru/forum/index.php?showtopic=11584&p=905308

Изменено пользователем Kirgudu
Ссылка на комментарий

Внезапно рухнула сеть, поэтому не отписывался.
Описание теста: платформа ТЧ 1.0006(топология), встроено расширение луа от артоса(by RvP), вернул родной xrLua - результаты теста теже. (Заодно проверил на 4 патче(+от солянки) с чистой геймдатой) - также вставляет не в 1ю позицию.)

  тестовый код (Показать)
Изменено пользователем Xdlic
Ссылка на комментарий

При работе с таблицей следует придерживаться одного из двух стилей:

- только как с обычным массивом, используя table.insert\remove и т.д.

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

Смешивать их не стоит. В SciTE с Lua 5.1 проблемы нет. А современный Lua - версии 5.3 - ругается на вставку элемента  с помощью table.insert за пределы границ - bad argument #2 to 'insert' (position out of bounds).

Ссылка на комментарий

@Xdlic

Да, иногда в сталкере стандартные действия Lua ведут себя совсем не так.
Когда то меня чуть не предали анафеме за мои высказывания в сторону ненормальности сталкеровского Lua. Но уже который раз это подтверждается :)
Что там сделали с Lua я не знаю, но ...
Значение "nil" хоть и обозначает отсутствие значения, всё-таки это одно из значений Lua, в отличии от отсутствия вообще какого-либо значения.
Возьми к примеру функции :
function f()
    return
end
и
function f()
    return nil
end
Первая не возвращает ничего, а вторая возвращает значение. nil ведь тоже значение.
Видимо в сталкере разрабы как-то акцентировали на этом внимание, поэтому такие результаты.
В любом случае этот вопрос решается просто.
Ты используешь :
for i = 1, #tt do tt[i] = nil end
На самом деле ты присваиваешь полям значения (nil).
А нужно удалять поля :
for i = #tt, 1, -1 do
    table.remove(tt, i)
end
Изменено пользователем Nazgool
  • Согласен 2
Ссылка на комментарий

 

 

  Nazgool писал(а):
Значение "nil" хоть и обозначает отсутствие значения, всё-таки это одно из значений Lua, в отличии от отсутствия вообще какого-либо значения.

Прости?

Очень интересно высказывание, почему ты так решил?

Freedom

Ссылка на комментарий

@_Призрак_

function f()
    return
end

print(f()) --> ничего
print(type(f())) --> bad argument #1 to 'type' (value expected) т.е. Lua значения нет

function f()
    return nil
end

print(f()) --> nil
print(type(f())) --> nil -- а тут значение есть. nil ведь одно из 8-ми значений Lua
Изменено пользователем Nazgool
Ссылка на комментарий
  Nazgool писал(а):
А нужно удалять поля

Давайте оставим этот момент в стороне. По отношению к индексным массива в сталкере вообще никак иначе обращаться категорически не рекомендую(как раз из за необновляющегося счетчика).

Собственно я отправил свое сообщение с мыслью, что получается в движке сталкера функции добавки/удаления реагируют на изменения таблицы совсем не так, как функция #t.

Вопрос имел целью узнать, как влиять на выбор текущей позиции в этих самых table.insert/remove.

Если, допустим, сделать простую обертку, которая предварительно будет определять конец индексного массива, то сами эти функции будут обрабатывать перестановку nil из одной ячейки в другую до сгенерировавшегося при первом вызове внутри них счетчика. Это конечно не особо сказывается на производительности, но сам факт имеет место быть.

Пример обертки, которая корректирует значение позиции текущего конца индекса



function insert_two(tab, pos_or_val, val)
    if val then
        table.insert(tab, pos_or_val, val)
    else
        table.insert(tab, #tab+1, val)
    end
end

Но это не отменяет того факта, что выйдя за пределы первоначального диапазона мы получим результат, когда начало таблицы наползает на ее конец

Изменено пользователем Xdlic
Ссылка на комментарий

@Xdlic

Зачем обертка? Вставлять стандартным способом, только принудительно указывать место вставки

table.insert(tt, #tt+1, "value")

#tt как раз и определит длину массива, а +1 поставит значение в конец.

А если делать обертку, то так, чтобы не навредить  вызовам table.insert в других скриптах

do
    local old_insert = table.insert
    function table.insert(t,p,v)
        old_insert(t, v and p or #t+1, v or p)
    end
end
Изменено пользователем Nazgool
Ссылка на комментарий
  Xdlic писал(а):

Собственно я отправил свое сообщение с мыслью, что получается в движке сталкера функции добавки/удаления реагируют на изменения таблицы совсем не так, как функция #t.

А почему они должны реагировать так же, как #t?
Ссылка на комментарий
  07.05.2015 в 08:28, abramcumner сказал:

А почему они должны реагировать так же, как #t?

Хотя бы затем, что имено если бы они реагировали также как #t, то это позволяло бы работать в сталкере с концом строки по упрощенному варианту t[#t+1] = val и t[#t] = nil вместо вызовов функций. В чистом луа как раз это и работает.

Никто не исследовал вопрос, где хранятся эти созданные счетчики? В недоступной части таблиц или где-то внутри движка Lua/Сталкера?

Upd:

  Цитата
insert работает абсолютно так же.

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

Ну хорошо, раз в сталкере нельзя работать с индексами по упрощенному варианту, значит будем каждый раз вызывать соответстующие функции... а если одновременно нужно этими инсертами забить 100500 значений в таблицу, которые заранее нельзя задать? Мы получим ощутимый нагруз от этих 100500 вызовов функции table.insert(ну ладно, пусть еще можно ссылку хранить локально). Или в этом случае полностью придется отказаться от индексных массивов и получать случайный перебор элементов из pairs().

Upd2:

И да, смысла в предложенной обертке меньше, чем 0. Чтобы она работала, нужно в ней получать доступ к счетчику и вручную его менять.

Upd3:

  Карлан писал(а):
Внезапно работает. 

Видимо я и вправду не умеею внятно изъяснять свои мысли/идеи. Твой вариант уже не будет работать совместно с table.insert/remove. Стоит их один раз вызвать и счетчик перестает зависеть от структуры таблицы. Про индексный массив с 100500 строк, тогда уж проще сделать обертку не вокруг самих функций, а вокруг метода. Т.е. реализуем свои table.insert_new/remove_new

function table_insert_new(t, pos_or_val, val)
    local end_pos = #t
    if val then
        if pos_or_val < end_pos then
            for i = end_pos, pos_or_val, -1 do
                t[i] = t[i-1]
            end
        else
            t[pos_or_val] = val
        end
    else
        t[end_pos+1] = val
    end
end

И подобное для remove, вроде алгоритм правильно описал

В результате не будет этого статического счетчика позиции для добавления/удаления, который я вижу в сталкере. А самое главное - можно будет спокойно работать как с t[#t+1] = val, так и с новой версией вставки значений в СЕРЕДИНУ индексного массива.

Изменено пользователем Xdlic
Ссылка на комментарий

@Xdlic, воистину ты занимаешься фигней, insert вставляет значение в nil или в конец, а #t получает количество элементов в таблице тоже по своим условиям, в зависимости есть nil в конце или нет, в итоге мы видим что твоя обертка вообще не несет никакой смысловой нагрузки, если на конце будет nil, то твоя обертка вставит значение вместо первого попавшегося nil, insert работает абсолютно так же.
 


  Xdlic писал(а):

это позволяло бы работать в сталкере с концом строки по упрощенному варианту t[#t+1] = val и t[#t] = nil вместо вызовов функций

Внезапно работает. 
local a = {}
a[#a+1] = 1
log(a[1])

 

 

  Xdlic писал(а):
нигде недоступен

можешь рубить последний элемент, потом работать, потом его назад вставлять.


я у себя с этим боролся с помощью pairs, вполне нормально выглядит.

Изменено пользователем Карлан
Ссылка на комментарий
  07.05.2015 в 08:57, Карлан сказал:

@Xdlic, воистину ты занимаешься фигней.

Будет время - посмотрю, что там внутри этих таблиц, вдруг счетчик хранится в метаданных самой таблицы.

Ладно, оставим в покое этот болезненный вопрос урезанного сталкерского Lua, интересно, какие еще особенности языка  ПЫСы сумели сломать к релизу?

Ссылка на комментарий
  Xdlic писал(а):

Хотя бы затем, что имено если бы они реагировали также как #t, то это позволяло бы работать в сталкере с концом строки по упрощенному варианту t[#t+1] = val и t[#t] = nil вместо вызовов функций.

Ну и работай так сейчас. Что мешает?

 

  Цитата

В чистом луа как раз это и работает.

Что такое чистое луа?

@Xdlic, попробуй для получения "внутреннего счетчика" использовать table.getn(t).

  • Спасибо 1
Ссылка на комментарий
  abramcumner писал(а):

попробуй для получения "внутреннего счетчика" использовать table.getn(t).

 

    Не обратил ранее на эту функцию внимания, считая ее аналогичной #. Проверил заодно и table.setn - да, эти функции как раз и позволяют получать и задавать "счетчик" с которым работают функции вставки/удаления. Можно ручками забивать строки через t[#t+1] = val, а затем обновлять его table.setn(t, #t) и стандартные insert/remove будут "видеть", что с таблицей что-то случилось :).. и соответственно будут обрабатывать также и новые данные.

Но... зачем-то их ведь удалили из стандартного набора Lua-функций. В SciTe-ru пишет: 'setn' is obsolete.

 

P.S. Споры о том, можно ли так делать или это "моветон" пропущу мимо ушей.

Ссылка на комментарий
  Xdlic писал(а):

Но... зачем-то их ведь удалили из стандартного набора Lua-функций. В SciTe-ru пишет: 'setn' is obsolete.

Потому что table.insert/remove стали работать через #t. Но оператор решетка не всегда был в Луа.
Ссылка на комментарий

Столкнулся с необходимостью сравнить две переменные типа userdata (копаю gui классы из луа и там возникла в этом потребность) . Но меня ждал Великий Облом в виде ошибки:

 

LUA error: No such operator defined
В начале вылетел при проверке на неравенство, потом та же ошибка и при проверке на равенство...

Выдержка из руководства: "...и не имеет предопределенных операций в Lua, за исключением присваивания и проверки на равенство."

 

Вот так, в иных сборках это ошибки не вызывает, а в сталкере похоже метаметода сравнения двух объектов нет. По крайней мере rawequal выдает вменяемые данные, придется или пользоваться им или делать сравнение по меткам.

Ссылка на комментарий
  Xdlic писал(а):

Столкнулся с необходимостью сравнить две переменные типа userdata

В сталкере юзердаты так нельзя сравнивать.

 

  Xdlic писал(а):

копаю gui классы из луа и там возникла в этом потребность

Не уверен, что именно это тебе нужно, но попробуй нечто вроде tostring(CUIStatic) == tostring(CUIStatic). Изменено пользователем Shadows
Ссылка на комментарий

@Xdlic

Действительно, стандартное сравнение пользовательских данных в сталкере не работает.

Но это легко изменить, используя расширение lua.

Прежде всего стоит определить утверждения, касающиеся lua в игре, которые и помогут в решении.

 

1. Для типа 'userdata' установлена единая метатаблица.

    P.S. Категорично утверждать не буду, не все проверял, но например для UI окон и для

    Волка она едина.

    Это позволяет предположить, что если для таких различных объектов метатаблица едина,

    то она едина и для всех остальных.

 

2. Метаметод '__eq' вызывается только при сравнении двух юзердат (тот, что не работает).

    Сравнение 'userdata' == 'другой тип данных' обрабатывается обычным образом.

 

3. Поскольку при сравнении двух типов 'userdata' вызывается метаметод '__eq', то результат

    сравнения нужно произвести без вызова метаметода. Функция 'rawequal' именно это

    и делает.

 

Отсюда следует, что можно переопределить метаметод '__eq', даже не сохраняя ссылку на

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

local userdata_mt = debug.getmetatable(CUIStatic())

function userdata_mt.__eq (a,
    return rawequal(a,
end

Вместо "CUIStatic()" можно использовать любое получение 'userdata'.

Ну и наконец вызов этого кода необходимо поставить на 'net_spawn', т.к. после

каждой загрузки новые данные поля 'userdata_mt.__eq' будут зачищаться.

Изменено пользователем Nazgool
Ссылка на комментарий
  Nazgool писал(а):

Отсюда следует, что можно переопределить

метаметод '__eq', даже не сохраняя ссылку на

прежний, т.к. этот метод больше ни для чего не

нужен, и ничего не затрагивает.

В результате код станет зависимым от этой правки. Метаметоды - неизбежное зло, и от важности их применения они не становятся менее злыми. В Lua нет инлайна, а следовательно каждая новая функция-обертка это неоправданное увеличение накладных расходов на один шаг алгоритма.

 

  немного скептиса (Показать)
Изменено пользователем Xdlic
  • Нравится 1
Ссылка на комментарий

@Xdlic

Вы наверное не полностью поняли о чем я писал.
 
Во-первых скажу, что если Вы ничего не будете делать, т.е. оставите всё как есть,
то это не отменит вызова стандартного метаметода при сравнении двух юзердат ))
 
Во-вторых вызов этого метаметода не приводит к результату. Вернее приводит к
результату печальному.
 
В-третьих. Раз метаметод вызывается, то предположительно внутри что-то присходит. И на это
затрачивается некое кол-во шагов алгоритма. Так почему не сделать правильно, т.е. выбросить
прежние "накладные расходы", как Вы говорите, и не заменить своими.
Вы должны были заметить, что это не обертка для прежнего "__eq", это новый метод "__eq".
 
В-четвертых, каким образом код станет зависимым от этой правки, если этот метаметод,
повторю, вызывается только! при сравнении двух юзердат, и более того - результат его работы плачевен.
Что мы теряем?
 
Ну и в-пятых пользуемся привычным сравнением "==" "~=" не задумываясь, - "А не юзердаты ли
сравниваемые переменные?"
Изменено пользователем Nazgool
Ссылка на комментарий

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

Комментарии могут оставлять только зарегистрированные пользователи

Создать аккаунт

Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!

Зарегистрировать новый аккаунт

Войти

Есть аккаунт? Войти.

Войти
  • Недавно просматривали   0 пользователей

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