Вопросы Разработчикам Скриптов, вопросы по скриптам (мелкие вопросы) |
Здравствуйте, гость ( Вход | Регистрация )
Вопросы Разработчикам Скриптов, вопросы по скриптам (мелкие вопросы) |
5.6.2009, 6:55
Сообщение
#521
|
|
Самый главный активист :-D Группа: Модераторы Сообщений: 2 790 Регистрация: 29.6.2008 Из: г. Тула Пользователь №: 97 Спасибо сказали: 440 раз |
хм, кроме пробегания циклом по таблице, особо вариантов нет!
|
|
|
5.6.2009, 8:45
Сообщение
#522
|
|
Главный ра******й тут... Группа: Главные администраторы Сообщений: 1 727 Регистрация: 18.5.2008 Из: RF, 2la Пользователь №: 1 Спасибо сказали: 776 раз |
А что если задуматься о кешировании? Допустип так же добавляем метатаблицу с функцией добавления в таблицу, а там уже увеличиваем счетчик, доступ к нему можно так же сделать по вызову функции таблицы tTable(), вот вам идея без пробега по всей таблице.
|
|
|
5.6.2009, 12:50
Сообщение
#523
|
|
RusHub team lead Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз |
Так можно сделать, однако, цеплять к каждой таблице метатаблицу не очень удобно.
Причём тут надо учитывать ещё и то, что таблицы в lua передаются по ссылке, поэтому для разных таблиц нужно будет писать разные метатаблицы. Пример реализации двух одинаковых один в один метатаблиц: Код -- первая метатаблица -- local mt1 = { __indx = 0 } function mt1:len() return mt1.__indx end function mt1:__newindex(key, val) if not rawget(self, key) then mt1.__indx = mt1.__indx + 1 end if key ~= "__indx" then rawset(self, key, val) end end mt1.__index = mt1 -- вторая (такая же) метатаблица -- local mt2 = { __indx = 0 } function mt2:len() return mt2.__indx end function mt2:__newindex(key, val) if not rawget(self, key) then mt2.__indx = mt2.__indx + 1 end if key ~= "__indx" then rawset(self, key, val) end end mt2.__index = mt2 Тест: Код tTable = {} setmetatable(tTable, mt1) tTable.a = {} tTable.b = {} tTable[4] = 5 tTable1 = {} setmetatable(tTable1, mt2) tTable1.a = {} tTable1.b = {} Core.SendToAll(tostring(tTable:len())) Core.SendToAll(tostring(tTable1:len())) Поэтому легче будет пробежать 1 раз по всей таблице, ничего страшного в этом нет. |
|
|
5.6.2009, 13:23
Сообщение
#524
|
|
Главный ра******й тут... Группа: Главные администраторы Сообщений: 1 727 Регистрация: 18.5.2008 Из: RF, 2la Пользователь №: 1 Спасибо сказали: 776 раз |
Типа
Код function GetIndexesCount(tTable) local iCnt = 0 for _ in pairs(tTable) do iCnt = iCnt + 1 end return iCnt end И вот еще интересно будет ли быстрее так: Код function GetIndexesCount(tTable) local tT = {} for _ in pairs(tTable) do table.insert(tT, true) end return #tT end Проверил: 2 функция проигрывает по времени в 2 раза при 100000 записях в таблице... |
|
|
5.6.2009, 15:07
Сообщение
#525
|
|
Постоялец Группа: Пользователи Сообщений: 454 Регистрация: 17.10.2008 Из: Новосибирск Пользователь №: 825 Спасибо сказали: 90 раз |
Nickolya
А как считаешь время отработки задачи, научи? ;) Я пробовал с помощью os.clock() - сходу ничего не получилось. Получается сравнивать только задачи, которые выполняются дольше, чем 1 секунда. Вот тут был затронут вопрос о таймерах и счетчиках, в начале мая. Наконец дошли руки, обкатал модель реализации срабатывания разных функций по таймеру с разной периодичностью. Глобальный счет считает себе и считает, вперед к победе коммунизма, а каждая из трех функций срабатывает строго по заданному периоду, один раз в 15, 40 и 65 секунд (в примере). Может, кому-нибудь пригодится. Код local sAdminNick = "Ваш ник"
local iPeriod1 = 15 local iPeriod2 = 40 local iPeriod3 = 65 local iGlCnt = 0 function Main() SetTimer(1000) StartTimer() end function OnTimer() iGlCnt = iGlCnt + 1 SendToNick(sAdminNick, "iGlCnt = "..iGlCnt) local iCount1 = CalcCount(iPeriod1) local iCount2 = CalcCount(iPeriod2) local iCount3 = CalcCount(iPeriod3) if iCount1 == iPeriod1 then Launch1(); end if iCount2 == iPeriod2 then Launch2(); end if iCount3 == iPeriod3 then Launch3(); end end function CalcCount(iPeriod) if iGlCnt < iPeriod then return iGlCnt elseif iGlCnt >= iPeriod then local iInt,iPart = math.modf(iGlCnt/iPeriod) if iPart == 0 then return iPeriod else return iGlCnt - (iPeriod * iInt ) end end end function Launch1() SendToNick(sAdminNick, "Функция 1 запуск") end function Launch2() SendToNick(sAdminNick, "Функция 2 запуск") end function Launch3() SendToNick(sAdminNick, "Функция 3 запуск") end |
|
|
5.6.2009, 15:23
Сообщение
#526
|
|
RusHub team lead Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз |
Быстрота выполнения определяется в процессе дебага кода.
По поводу таймеров для api1, есть более оптимальные методы (см. как это реализовано в хуббе) |
|
|
18.6.2009, 14:52
Сообщение
#527
|
|
Постоялец Группа: Пользователи Сообщений: 454 Регистрация: 17.10.2008 Из: Новосибирск Пользователь №: 825 Спасибо сказали: 90 раз |
"Упс", как говорится. Не добрался до Хуббы, но спасибо Berkut'у, для кого-то изложившему в чате принцип мультитаймера для API1, понял что перемудрил и изменил свой мультитаймер. Не зря говорят - грамотно сформулированная задача это полдела.
Например вот так : Код local sAdminNick = "[INT]district" -- Впишите свой ник -- Периоды срабатывания в секундах : local iPeriod1 = 15 local iPeriod2 = 40 local iPeriod3 = 65 -- Каунтеры для каждого субтаймера : local iCount1 = 0 local iCount2 = 0 local iCount3 = 0 function Main() SetTimer(1000) StartTimer() end function OnTimer() iCount1 = iCount1 + 1 iCount2 = iCount2 + 1 iCount3 = iCount3 + 1 SendToNick(sAdminNick, "iCount1 = "..iCount1.." iCount2 = "..iCount2.." iCount3 = "..iCount3) if iCount1 == iPeriod1 then Launch1(); iCount1 = 0; end if iCount2 == iPeriod2 then Launch2(); iCount2 = 0; end if iCount3 == iPeriod3 then Launch3(); iCount3 = 0; end end function Launch1() SendToNick(sAdminNick, "Функция 1 запуск") end function Launch2() SendToNick(sAdminNick, "Функция 2 запуск") end function Launch3() SendToNick(sAdminNick, "Функция 3 запуск") end Еще есть ВОПРОС. Есть центральный модуль, есть подчиненный. У подчиненного модуля есть таблица local tWorkTable и таблица-интерфейс со значениями настроек модуля tSettings, вызываемая центральным модулем при запуске. Задача - по определенной команде вытаскивать изменяемую во времени локальную рабочую таблицу подчиненного модуля (tWorkTable), чтобы сохранять ее или производить над ней другие операции. Пока что это делается так : В центральном модуле получаю таблицу из подчиненного модуля так : Код local tWorkTable = assert(loadstring(tSettings.GetActualTable))() при этом в подчиненном модуле вот такая вот ситуация : Код local tWorkTable = { ... } local tSettings = { GetActualTable = "return ActualTable()", ... ... } function ActualTable() return tWorkTable end Как бы это сделать проще и элегантнее? Чувствую что можно, а как именно - пока тупик. |
|
|
18.6.2009, 15:55
Сообщение
#528
|
|
RusHub team lead Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз |
Хехе. Действительно накрутил слишком заумно как-то))))
Главный модуль: Код local tWorkTable = ActualTable() Подчинённый модуль: Код local tWorkTable = { ... } function ActualTable() return tWorkTable end Однако, из-за того, что таблицы в lua передаются по ссылке, а не по значения, то доступ к записи в таблицу tWorkTable будет доступен в обоих модулях. А ты, я так понимаю, хотел реализовать некий принцип инкапсуляции |
|
|
18.6.2009, 17:18
Сообщение
#529
|
|
Постоялец Группа: Пользователи Сообщений: 454 Регистрация: 17.10.2008 Из: Новосибирск Пользователь №: 825 Спасибо сказали: 90 раз |
Дело в том, что модулей несколько, и у каждого своя локальная таблица tWorkTable, причем строение этих таблиц неодинаковое. А хотелось сохранить локальность таблиц подчиненных модулей и стандартное имя tWorkTable, при обработке этих таблиц разными циклами, разными командами. Собственно сами эти циклы в еще одном модуле находятся, который как бы универсален для всех этих tWorkTable, принадлежащих модулям, и предназначен для их обслуживания : автоочистки по опр. признаку, автосохранения, сортировки и т д.
А эти циклы универсального модуля запускаются из главного ( центрального ) модуля, вот такая вот ситуация. Таблица tSettings каждого подчиненного модуля, которая вызывается в центральный модуль при старте скрипта, хранит индивидуальные параметры этих таблиц и задачи для циклов (вызываемые с помощью loadstring). Вот как-то так... |
|
|
18.6.2009, 17:43
Сообщение
#530
|
|
RusHub team lead Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз |
Проще было бы воспользоваться ООП. Тут как раз отдельный модуль - это один объект.
Я не понимаю в чём проблема? Напиши в каждом модуле свою функцию ActualTable_mod1(), ActualTable_mod2() и тд. Или как вариант возвращать ссылку на данные при подключении модуля Главный модуль: Код local tWorkTable = require"mod1" Подчинённый модуль (mod1.lua): Код local tWorkTable = { ... }
return tWorkTable |
|
|
19.6.2009, 2:41
Сообщение
#531
|
|
Постоялец Группа: Пользователи Сообщений: 454 Регистрация: 17.10.2008 Из: Новосибирск Пользователь №: 825 Спасибо сказали: 90 раз |
Setuper
Цитата Я не понимаю в чём проблема? Напиши в каждом модуле свою функцию ActualTable_mod1(), ActualTable_mod2() и тд. Так оно и есть, в каждом модуле своя функция, которая возвращает актуальную (висящую в ОЗУ, и необязательно сохраненную на диск) рабочую таблицу. А проблема вот в чем : нужно, чтобы значение таблицы-интерфейса tSettings.GetActualTable было увязано, т е включало все необходимые сведения для вызова соответствующей актуальной таблицы. Опять-таки, это в принципе и реализовано ( через loadstring и хранение этого самого стринга в tSettings.GetActualTable), а вопрос был - можно ли это сделать проще и элегантнее. Пробовал вместо loadstring хранить в поле tSettings.GetActualTable функцию вроде Код function() return tWorkTable end - не прошло.Разные другие варианты пробовал, ни один не прошел, поэтому обратился за помощью.Вот про require не совсем понял. Ты писал вот что: Цитата Если файл загружается 1 раз, то без разницы. Если не один раз, то require выгоднее, если не происходит изменений в этом файле, иначе dofile Изменения в файле ( рабочей таблице) - происходят, по ходу деятельности скрипта, т е таблица иногда изменяется, иногда сохраняется на диск, поэтому метод вызова везде dofile. Или что имелось в виду под "изменениями в этом файле"? Хорошо бы поподробнее, или ссылку на доходчивый и развернутый материал по теме. |
|
|
19.6.2009, 20:23
Сообщение
#532
|
|
RusHub team lead Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз |
Изменения именно в файле - вот что имелось ввиду. То есть за всё время работы скрипта функция require загрузить в память код только 1 раз, при последующих обращениях во время работы скрипта к данной функции она будет брать уже загруженный код.
|
|
|
21.6.2009, 4:54
Сообщение
#533
|
|
Постоялец Группа: Пользователи Сообщений: 454 Регистрация: 17.10.2008 Из: Новосибирск Пользователь №: 825 Спасибо сказали: 90 раз |
Вчера начал потихоньку пробовать работать с метатаблицами. Получается вот что. В каком-то подчиненном модуле создается таблица-интерфейс с настройками, и на основании этих настроек создается метатаблица для этой таблицы, с функциями. (если я правильно понял, внутри одной таблицы нельзя для второго элемента-функции использовать переменную, записанную в первом элементе - например если в первом элементе таблицы tTable записано
Код bWork = true , то во второй нельзя записать Код function() if tTable.bWork then ... end; end . Или все-таки можно?) Потом таблица-интерфейс вызывается в центральный модуль. Таким образом, центральный модуль имеет не только полную информацию о настройках подчиненного модуля, но и перечень функций, которые нужно по заданному в этих настройках алгоритму применять к! вот тут самое важное. Получается так, что рабочая таблица с какими-то изменяемыми во времени и иногда сохраняемыми на диск данными, элементарно вызывается для обработки в центральный модуль не по имени, и не по чему-то другому, а способом Код local tWorkTable = getmetatable(tSettings).tWorkTable ???Если это мне не кажется, то это же просто волшебная черная магия, о которой даже и помыслить не смелось Тогда все предыдущие вопросы с необходимостью использования loadstring - снимаются... Получается, что вызвать рабочую таблицу модуля можно когда угодно и куда угодно, не используя ее имя, и вне зависимости от изменений, происходящих в этой таблице. Получается принцип, который в радиоэлектронике называют "гальванической развязкой" и который реализован в таком простом и нужном приборе, как "оптопара" ( светодиод-фотодиод или светодиод-фоторезистор). Так ли это? Не сон ли это?? ... и еще прицепом небольшой вопрос. В центральном модуле есть набор констант, строки с типовыми выражениями вроде "$UserCommand 1 3" и т п Имеет ли смысл создавать в каждом модуле аналогичный набор локальных констант, или все, что можно взять с центрального модуля, пусть периферийные модули от него и получают? |
|
|
21.6.2009, 11:38
Сообщение
#534
|
|
RusHub team lead Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз |
Ты явно изобретаешь велосипед))) Проще воспользоваться ООП. Возможно я не совсем понимаю что ты хочешь сделать, но уж больно это похоже на ООП.
Первый вопрос, ответ - можно (даже без классов): Код tTable = { bWork = true, Func = function(self) if self.bWork then ... end end } Вопрос два, ответ - это действительно так. Метатаблица - это отдельная таблица, которую мы подключаем к другой таблице, то есть метатаблица и таблица занимают различные адреса в памяти. Чтобы ответить на "прицеп", нужно иметь понятие о том, что ты хочешь реализовать. |
|
|
21.6.2009, 14:54
Сообщение
#535
|
|
Постоялец Группа: Пользователи Сообщений: 454 Регистрация: 17.10.2008 Из: Новосибирск Пользователь №: 825 Спасибо сказали: 90 раз |
Ладно)) Не все сразу. Даст Бог доделаю и выложу, тогда, может быть, если будет на то желание и время, можно будет предметно посмотреть.
Второй пункт - самый существенный. Если раньше приходилось по рабоче-крестьянски - вызывать требуемую таблицу строго по имени, то теперь: есть пять модулей, в каждом из них таблица с одинаковым ничего не выражающим именем tInterFace. К каждой такой таблице прикреплена метатаблица с еще менее что-либо выражающим стандартным именем tMetaInterFace, и полем .tWorkTable, которое равно существующей в каждом из пяти модулей рабочей таблице tWorkTable. И вот, О ЧУДО ! в центральном модуле в нужный момент, непонятно по какому признаку и принципу, через непонятно какие третьи руки, возникает и попадает в обработку именно та таблица, которая требуется )))) По первому вопросу. Перепроверил еще раз, попробовал запустить такой код : Код local tTable = { bWork = true, Func = function() if tTable.bWork then SendToNick("[INT]district", "РАБОТАЕТ") end end, } function Main() tTable.Func() end Результат :lua:4: attempt to index global 'tTable' (a nil value) Значит, все верно : в одной таблице не могут уживаться условие, и функция, которая выполняется или не выполняется следуя этому условию. Поэтому условия (настройки) храним в локальной таблице, а функции, которые должны выполняться или не выполняться по этим условиям, храним в метатаблице. Так получается? Или какая тут ошибка? И что значит в приведенном выше примере загадочное слово self ? До сих пор в неведении. |
|
|
21.6.2009, 15:12
Сообщение
#536
|
|
RusHub team lead Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз |
self - это и есть tTable, но в неявном виде.
Только вместо функции надо вызывать метод. Вот так будет работать: Код tTable = { bWork = true, Func = function(self) if self.bWork then SendToNick("[INT]district", "РАБОТАЕТ") end end } function Main() tTable:Func() end Когда мы пишем tTable:Func(), то это равносильно записи tTable.Func(tTable). Теперь должно быть понятно, что в качестве параметра self в методе выступает таблица. Можно пойти намного дальше и реализовать так называемый "принцип полиморфизма": Код tTable = { bWork = true, Func = function(self) if self.bWork then SendToNick("[INT]district", "РАБОТАЕТ") else SendToNick("[INT]district", "НЕ РАБОТАЕТ") end end } tTable2 = { bWork = false, } function Main() tTable.Func(tTable2) end Вот последний пример это уже некое подобие полиморфизма в ООП. |
|
|
21.6.2009, 16:28
Сообщение
#537
|
|
Постоялец Группа: Пользователи Сообщений: 454 Регистрация: 17.10.2008 Из: Новосибирск Пользователь №: 825 Спасибо сказали: 90 раз |
Ясно )) ( пробовал кстати сразу и с self аргументом, нечто подобное интуитивно предполагая, но что-то где-то проглядел, и не запустилось).
Но все-таки думаю пока разделить настройки и функции , хотя теперь вижу, что теоретически можно и в одну таблицу все упихать. |
|
|
6.7.2009, 22:13
Сообщение
#538
|
|
Продвинутый участник Группа: Пользователи Сообщений: 173 Регистрация: 26.1.2009 Из: Saratov Пользователь №: 1 965 Спасибо сказали: 7 раз |
Всем привет! Давно меня тут не было!!! Пардон за оффтоп...вопрос срочный возник...! Есть идеи как (и чем) можно закрыть доступ к TCP подключениям (ну или вообще всем подключениям) по mac ?
|
|
|
8.7.2009, 1:35
Сообщение
#539
|
|
Постоялец Группа: Пользователи Сообщений: 454 Регистрация: 17.10.2008 Из: Новосибирск Пользователь №: 825 Спасибо сказали: 90 раз |
Вот наконец пора решать еще один давно интересующий вопрос.
Есть набор функций ( собранных в таблицу), с однотипными именами, различающимися цифрой : Rule1, Rule2 и т.д. Как организовать цикл отработки всех функций по порядку? Код fFunc = function() for i=1,2 do return tTable.Rule..i(); end; end тут не подходит : Код attempt to call local 'i' (a number value) ... и еще вопросик. Нужно записать построчно файл, каждая строка строка должна заканчиваться символом LF (line feed, код 10 ). "\r" - дает CR (carriage return, возврат каретки, как я понимаю) "\n" - дает CR LF string.char(10) - тоже CR LF Как быть? |
|
|
8.7.2009, 2:24
Сообщение
#540
|
|
Местный Группа: Неактивированные Сообщений: 908 Регистрация: 26.12.2008 Пользователь №: 1 574 Спасибо сказали: 1406 раз |
1)
Код fFunc = function() for i=1,2 do return tTable["Rule"..i](); end; end 2) Код local f = io.open(filename,"wb")
|
|
|
Похожие темы
|
Сейчас: 23.11.2024, 21:20 |