Dennis_Chikin 3 658 Опубликовано 4 Января 2015 Поделиться Опубликовано 4 Января 2015 (изменено) С чего начинать и где взять. Установка 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 Изменено 2 Марта 2015 пользователем Kirgudu Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Ссылка на комментарий
abramcumner 1 145 Опубликовано 19 Апреля 2015 Поделиться Опубликовано 19 Апреля 2015 Вот не хотел же влезать Всё это надо читать в документации, а не хватать по форумам. Луа: 2.1 В Луа 8 типов: nil, boolean, number, string, function, userdata, thread, and tableИз них 4 типа: nil, boolean, number, string - являются типами-значениями. Это значит, например, что при передаче в функцию, передается их копия. function f(a) a = 5 end local x = 7 f(x) print(x) -- выведет 7, потому что в функцию передалась копия Оставшиеся 4 типа: function, userdata, thread, and table в документации луа названы "objects" - я бы сказал по-русски ссылочный тип. Перменные таких типов хранят не сами значения, а ссылки на них. function g(a) a.y = 5 end local x = {y = 7} g(x) print(x.y) -- выведет 5, потому что в функцию передалась ссылка и по этой ссылки значения можно менять. Если программист до луа изучал си , то все ссылочные типы можно воспринимать как константные указатели, чем они на самом деле и являются. Правда константных указателей в C вроде не было, они только в C++ появились Ссылка на комментарий
abramcumner 1 145 Опубликовано 19 Апреля 2015 Поделиться Опубликовано 19 Апреля 2015 Опс... Что-то про string я захотел посмотреть код. Точнее, много кода. Если это действительно так, то я перестаю понимать, как работает многое из того, что работает. Ну вот в частности вообще все таблицы.Замени в примерах выше числа на строки: 5 на "aa", 7 на "bb". Ничего не изменится. Приводи код, который непонятно работает. Ссылка на комментарий
Desertir 202 Опубликовано 19 Апреля 2015 Поделиться Опубликовано 19 Апреля 2015 выведет 7, потому что в функцию передалась копияДа, но почему этот пример такой? Вот сразу же дальше для ссылочных типов ты верно все пишешь, но если использовать функцию f(a) для них, тоже магии не произойдет, потому что ты переопределяешь аргумент, наружу это никак не уйдет в любом случае, будь там хоть value type хоть reference type. как-бы в сталкере они связаныЭто не дает нам права разводить откровенный оффтоп. Тут C++, и он закончился в начале этой страницы, но я надеюсь тред будет перенесен в тему Lua. 1 ТЧ 1.0004. SAP и Trans mod github Ссылка на комментарий
abramcumner 1 145 Опубликовано 19 Апреля 2015 Поделиться Опубликовано 19 Апреля 2015 @Desertir,Да, но почему этот пример такой? Вот сразу же дальше для ссылочных типов ты верно все пишешь, но если использовать функцию f(a) для них, тоже магии не произойдет, потому что ты переопределяешь аргумент, наружу это никак не уйдет в любом случае, будь там хоть value type хоть reference type.Не понял. Приведи другой пример... Я просто показал, что в луа есть типы-значения и ссылочные типы и чем они отличаются. Ну и у ссылочных типов в луа семантика указателей. Ссылка на комментарий
Dennis_Chikin 3 658 Опубликовано 19 Апреля 2015 Поделиться Опубликовано 19 Апреля 2015 local test_s1 = "" local test_s2 = "" local test_i = 0 function test( v ) end for i = 1, 10000 do test_s1 = test_s1 .. " " end local pt = profile_timer() pt:start() for i = 1, 10000 do test ( test_s1 ) end pt:stop() log( "info", "string 200000: %s", pt:time() ) local pt = profile_timer() pt:start() for i = 1, 10000 do test ( test_s2 ) end pt:stop() log( "info", "string 0: %s", pt:time() ) local pt = profile_timer() pt:start() for i = 1, 10000 do test ( test_i ) end pt:stop() log( "info", "int: %s", pt:time() ) string 200000: 30992.1328125 string 0: 231.48368835449 int: 216.08390808105 Таки да, действительно копирует. Прощай очередной "оптимизаторский" миф про "строки существуют только в одном экземпляре". Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Ссылка на комментарий
abramcumner 1 145 Опубликовано 19 Апреля 2015 Поделиться Опубликовано 19 Апреля 2015 @Dennis_Chikin, замерь еще передачу в функцию таблицы, в которой лежит очень длинная строка. Ссылка на комментарий
Desertir 202 Опубликовано 19 Апреля 2015 Поделиться Опубликовано 19 Апреля 2015 (изменено) Не понял. Приведи другой пример...Показать, что value type передаются по значению? У меня только 1 вариант приходит в голову, это надо получить их адреса и показать, что они разные. Но я не знаю как это сделать print variable address lua @Dennis_Chikin, омг, да ты о чем? Сам же приплетаешь способы передачи аргументов и сборщик, это к чему вообще? Есть 2 типа переменных - value type и reference type. Первый при передачи в функцию копируется, второй нет. У value type адреса будут отличаться, у reference type нет. Все. Точка. Никаких присваиваний, созданий переменных и прочей лабуды. Изменено 19 Апреля 2015 пользователем Desertir ТЧ 1.0004. SAP и Trans mod github Ссылка на комментарий
Dennis_Chikin 3 658 Опубликовано 19 Апреля 2015 Поделиться Опубликовано 19 Апреля 2015 (изменено) 2 Desertir: только код смотреть. Адреса же нам принципиально не показывают в явном виде. Собственно, имея в виду (господи, как же это и назвать-то теперь, чтоб очередной страницы флуда не получить) - ну, вы поняли - я бы вообще сделал банально: Если что-то передается в функцию - передается адрес (у нас внутри все равно не регистровые операции, а если и регистровые, то с предварительной загрузкой из стека). То есть, пока нет присваивания - по этому адресу и получаем. Как только присваивание - создаем новую переменную, и указатель выставляем на нее. В связке с концепцией "уборки мусора" оно кажется единственно правильным, и я думал, что именно так и работает. 2 abramcumner: ожидаемо, 246 для таблицы (vs 212 и 212 для "" и 0 ). Изменено 19 Апреля 2015 пользователем Dennis_Chikin Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Ссылка на комментарий
Xdlic 9 Опубликовано 30 Апреля 2015 Поделиться Опубликовано 30 Апреля 2015 Вопрос такой. Есть метод, перебирающий таблицу объектов и вызывающий у каждого объекта метод inject. Сам метод, в зависимости от ситуации может быть как собственно методом, так и переопределенной внешней функцией. Как, кроме объявления этих объектов в глобальной переменной, можно получить доступ к self внутри метода(непереопределенного)? Возможно мне нужно что-то про замыкания, но я в них толком не разобрался Этот метод также вызывает эту функцию. Т.е. мне нужно либо вызывать функцию внутри метода, либо вместо метода. for k, v in pairs(self.elements) do oActive_elem = v -- v:inject(...) -- если это метод, то вызываем его как метод v.inject(...) -- если это переопределенная функция, то передаем параметры как есть end Нужно, чтобы если поле объекта - метод, то можно было получить внутри метода доступ к self. А если поле объекта - функция, то избежать получения первым аргументом ссылки self на этот объект. Ссылка на комментарий
Desertir 202 Опубликовано 30 Апреля 2015 Поделиться Опубликовано 30 Апреля 2015 @Xdlic, весьма странное поведение. Объясни что ты хочешь сделать, у меня чувство, что ты выбрал не совсем верную стратегию. И еще, ты используешь LuaBind? ТЧ 1.0004. SAP и Trans mod github Ссылка на комментарий
Xdlic 9 Опубликовано 30 Апреля 2015 Поделиться Опубликовано 30 Апреля 2015 (изменено) Хочу реализовать в сталкере классы, в которых методы будут менять свое поведение в зависимости от параметров объекта(замещаться аналогичными методами). Пока это все в виде набросков, но схема предложенного выше такова: Есть класс (скажем 1), задачей которого являет обновление состояния массива объектов другого класса (2). В этом втором классе обновление может быть реализовано как в виде метода (при инициализации в метод inject подставляется нужный в данной ситуации метод), так и в виде функции (этот метод предназначен, в свою очередь для вызова сторонней функции). Можно конечно не заморачиваться и просто использовать обертку вида function element_class:inject(...) self.fun(...) end Когда не требуется производить дополнительных действий, но меня интересует, можно ли обойтись без обертки, подставляя в метод стороннюю функцию и обрабатывая доступ к self в методах inject_xxx() как-то иначе. Изменено 30 Апреля 2015 пользователем Xdlic Ссылка на комментарий
Desertir 202 Опубликовано 30 Апреля 2015 Поделиться Опубликовано 30 Апреля 2015 Определение метода и его вызов, это просто сахар в Луа. local some_object = { one = 1, two = 2 } --определили метод с "сахаром" function some_object:print_one() print("Print one: "..self.one) end --определили метод без "сахара" some_object.print_two = function(self) print("Print two: "..self.two) end some_object:print_one() --Print one: 1 some_object:print_two() --Print two: 2 some_object.print_one(some_object) --Print one: 1 some_object.print_two(some_object) --Print two: 2 --если так сильно надо заменить метод и чтобы он оставался методом, можно сделать так function print_three(self) print("Print three: "..self.three) end some_object.three = 3 some_object.print_two = print_three --пошалим some_object:print_two() --Print three: 3 some_object.print_two(some_object) --Print three: 3 Так можно сделать, но это скорее всего приведет к багам или "непредвиденным последствиям" (с). Для изменения поведения есть условные ветвления. ТЧ 1.0004. SAP и Trans mod github Ссылка на комментарий
Карлан 1 049 Опубликовано 30 Апреля 2015 Поделиться Опубликовано 30 Апреля 2015 @Xdlic, используй метатаблицы, в зависимости от условий переопределяешь метод. Для независимых таблиц подходит без всякого странного, с движком так уже не получится, там пока никак не получается (и не только у меня). Схема примерно такая, пишешь дефолтовый метод, пишешь остальные методы (отдельно или в таблицу тут как тебе удобнее), на вызове проверяешь условия которые тебе нужны и переопределяешь текущий метод с помощью метаметода на нужный. @Desertir, это очень грубо и я бы даже сказал несуразно. Ссылка на комментарий
Desertir 202 Опубликовано 30 Апреля 2015 Поделиться Опубликовано 30 Апреля 2015 @Карлан, переопределение метода вообще моветон. Ктото из команды написал метод paint а ты его переопределяешь, и пишешь туда сложение, а тот первый пытается чтото вывести на экран. Получается вообще не пойми что и огрести можно не слабо. Я резко против этого, поэтому и написал, что есть if ... then. я бы даже сказал несуразноПро твой способ могу сказать тоже самое. ТЧ 1.0004. SAP и Trans mod github Ссылка на комментарий
Карлан 1 049 Опубликовано 30 Апреля 2015 Поделиться Опубликовано 30 Апреля 2015 @Desertir, с такими выводами можно функцию переписать с таким же успехом. В переопределении нельзя использовать if-then? Это не мой способ, но его для этого и создавали. Можно написать условия и для сложения и для вывода на экран, причем тут командная работа я вообще не понял. Ссылка на комментарий
Xdlic 9 Опубликовано 1 Мая 2015 Поделиться Опубликовано 1 Мая 2015 (изменено) Xdlic, используй метатаблицы, в зависимости от условий переопределяешь метод. Это могло бы быть вариантом, но в целом в результате дает просто перенос выбора ветви поведения в другое место. Обработка вызова функции через метатаблицы по сути являются теми же ветвлениями, но они уже будут статичны для данного типа/класса. Определение метода и его вызов, это просто сахар в Луа. Если функция определена как метод, то self при ее вызове будет автоматически скрываться. Простая функция в этом случае будет вести себя несколько иначе - если вызвать ее как метод, параметры будут смещены вставкой self первым аргументом. Речь шла о замещении метода функцией, не расчитанной на получение self. И в первом посте было упомянуто - как вызвать метод (без двоеточия видимо?) и получить внутри него self не делая в заголовке каждой вариации метода лишних телодвижений с получением объекта, в котором метод был переопределен. Следует отметить, что вызов inject-метода через точку не подразумевает передачу туда self в явном виде, во время вызова, иначе это скатилось бы к тем же громоздким ветвлениям. Карлан, переопределение метода вообще моветон. Ктото из команды написал метод paint а ты его переопределяешь, и пишешь туда сложение, а тот первый пытается чтото вывести на экран. В чем-то вы правы, но.. Работа вариантов метода полностью определяется внутренним контекстом объекта и не зависит от передаваемых значений. В данном случае было задачей убрать затратные проверки при каждом обновлении. Заглянул по интересующему вопросу в мануал из шапки и подчерпнул кое-что интересное для себя. Изложенное мной выше достаточно легко реализовать с помощью замыканий - переносим объявления подобных функций в тело функции __init() и они автоматически в своем окружения получают переменную self (замыкаются на окружении объекта). Для этого нужно задавать такие функции через точку(не как методы класса), а внутри спокойно работать, как если бы эта функция была объявлена методом. class "element_class" function element_class:__init(name) ... function element_class.inject_std(...) -- функция через точку -- выполняем стандартные действия, self - ссылка на этот объект end function element_class.inject_greatdata_debug(...) log("DL_CALL, ELEMENT_CLASS:120 call greatdata_debug") -- выполняем нужные действия self:set_param("inject_std") -- меняем поведение интерфейса inject end if <стандартное состояние> then self.inject = self.inject_std elseif <куча проверок> then self:set_param("inject_greatdata_debug") end end function element_class:inject(...) -- выполняем действия для неинициализованного состояния объекта end -- функция для смены состояния объекта и текущего обработчика, ее по идее бы -- вообще реализовать в "приватной" форме, но пока не нашел элементарного варианта function element_class:set_param(param) -- передаем имя нового обработчика, к примеру -- а здесь переключаем состояние объекта и меняем значение element_class.inject self.inject = self[param] end Ну, вобщем виде, применение данной схемы управления методами достаточно "дорогое" и имеет смысл там, где слишком много действий нужно выполнить для определения - какую-же ветку использовать на этот раз? вместо этого мы сильно нагружаем инициатор, но его ведь нужно вызывать только один раз В целом такой подход к написанию кода имеет много тонкостей и не подходит в реализации типичных алгоритмов. Но с его помощью вполне возможно реализовать нечто вроде "приватных" переменных/функций, которые никак не получить извне объекта. Ну и на последок. Меня заинтересовала сама возможность изменять метод объекта так, чтобы он всегда соответствовал задаче, решаемой этим конкретным объектом на данный момент. Изменено 1 Мая 2015 пользователем Xdlic Ссылка на комментарий
Xdlic 9 Опубликовано 6 Мая 2015 Поделиться Опубликовано 6 Мая 2015 (изменено) В ходе своих наработок в Lua для сталкера сделал отметил несколько любопытных моментов: 1. По поводу функций table.insert, table.remove и оператора #: Понаблюдал за поведением этих операторов при различных условиях и у меня получается вот что. При первом обращении к этим операторам таблице задается счетчик последнего индекса(значение, возвращаемое #tb). При этом в самой таблице вполне могут на этот момент быть пустые значения, не отсекшиеся ввиду упрощенности бинарного поиска пропусков в индексе. После этого это значение не меняется, даже если занилить все элементы таблицы for i = 1, #tb do tb[i] = nil end При этом функции insert и remove продолжают работать со старым значением индекса, а вот оператор получения длины выдает, что таблица пуста. Собственно смысл: если сейчас попытаться вставить в таблицу значение table.insert(tb, value), то оно встанет как раз по месту мифического конца индексированной части. И мы получим массив вида: {nil, nil, nil, nil, nil, nil, nil, nil, nil, value}. В случае того же SciTe позиция последнего элемента обновляется при заниливании, а в сталкере этого не происходит. Собственно вопрос, можно ли как-то повлиять на значение этого внутреннего счетчика или следать метаметод, обновляющий его? Получается, что в сталкере задание значения по индексу n+1 счетчик попросту не обновляет, а функции вставки/удаления полей игнорируют текущую структуру таблицы. Upd: Забыл указать, версия ТЧ 1.0006 Изменено 6 Мая 2015 пользователем Xdlic Ссылка на комментарий
Nazgool 250 Опубликовано 6 Мая 2015 Поделиться Опубликовано 6 Мая 2015 (изменено) @Xdlic, После выполнения for i = 1, #tb do tb[i] = nil end у меня и в SciTE, и в игре функции insert и remove работают одинаково правильно, т.е. ставит 'value' в поле с индексом 1. Покажи весь код, на котором ты тестировал и получал таблицу {nil, nil, nil, nil, nil, nil, nil, nil, nil, value} Изменено 6 Мая 2015 пользователем Nazgool Ссылка на комментарий
Карлан 1 049 Опубликовано 6 Мая 2015 Поделиться Опубликовано 6 Мая 2015 @Xdlic, как это игнорируют? Нормально они работают, в т.ч. и на 6 патче, все обновляется, и оператор, и значения. Ссылка на комментарий
Nazgool 250 Опубликовано 6 Мая 2015 Поделиться Опубликовано 6 Мая 2015 @Карлан, Постучу сюда, ведь в ЛС не отвечаешь. Как там мой вариант переопределения? Работает? Ссылка на комментарий
Рекомендуемые сообщения
Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий
Комментарии могут оставлять только зарегистрированные пользователи
Создать аккаунт
Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!
Зарегистрировать новый аккаунтВойти
Есть аккаунт? Войти.
Войти