Что нового

[Новая функция] Возможно ли в AutoIt создать новый тип данных - массив функций?

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
Всю жизнь мечтал о такой конструкции как массив функций.

Я себе это представляю примерно так:
Код:
DIM $farray[4]()

FuncAssign($farray[0],_func1)
FuncAssign($farray[1],_func2)
FuncAssign($farray[2],_func3)
FuncAssign($farray[3],_func4)

$x = $farray[2]()


Возможно ли инициировать такую доработку в AutoIt ?
(хотя бы в сокращённом варианте - функции без параметров)
 

AZJIO

Меценат
Меценат
Сообщения
2,878
Репутация
1,194
C2H5OH
так?
Код:
Dim $farray[4]
For $i = 0 To 3
	$farray[$i] = '_func' & $i + 1
Next
$x = Call($farray[2])

Func _func1()
	MsgBox(0, 'Сообщение', '1')
EndFunc

Func _func2()
	MsgBox(0, 'Сообщение', '2')
EndFunc

Func _func3()
	MsgBox(0, 'Сообщение', '3')
EndFunc

Func _func4()
	MsgBox(0, 'Сообщение', '4')
EndFunc


В новой бета версии указатель на функции.
 
Автор
C2H5OH

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
AZJIO,
метод искуственный, основанный на том что это интерпритатор, но, наверное, так.
Сейчас попробую функции с параметрами сделать.
;D

CreatoR,
сейчас это не конкретно. Это мысль, которая периодически приходит. Обоснование необходимости такое же как и у обычных массивов - при работе с большим количеством функций хочется эвсё это дело упорядочить.
Если ищете рациональное зерно, то можем для примера взять работу оператора Select или Switch с большим количеством Case. Реализовано это как проверка всех подряд условий до нахождения подходящего. Я считаю что правильное применение массива функций более эффективно (не полностью заменяет, а во многих случаях будет эффективнее)
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
функции удобны тем, что при правильном выборе имени дают подсказку на выполняемое им действие. если сделать как ты хочешь то эта черта пропадет, т.к. придется либо держать в уме какой индекс что выполняет, либо то и дело заглядывать в список индекс-функция. я лично эффективности в этом не вижу. если же в скрипте много похожих функций с малым отличием – это лишь признак неправильно составленного скрипта и в большинстве случаев сводится к добавлению дополнительного параметра в одну единственную функцию, который при том или ином значении данного параметра будет выполнять действие вышеуказанных мелких функций.
 

beliy

Продвинутый
Сообщения
372
Репутация
72
В с++ (на котором написан Autoit) такое можно сделать используя массивы указателей, но не думаю что данный подход рациональный.
Чем вам не подходит такой вариант? Он намного проще и быстрее...

Код:
_farray(2);

Func _farray($value)
   Switch $value
		   Case 1
		   _func1()
		   Case 2
		   _func2()
		   Case 3
		   _func3()
		   Case 4
		   _func4()
   EndSwitch
EndFunc

Func _func1()
   MsgBox(64, "comand1", "comand1")
EndFunc

Func _func2()
   MsgBox(64, "comand2", "comand2")
EndFunc

Func _func3()
   MsgBox(64, "comand3", "comand3")
EndFunc

Func _func4()
   MsgBox(64, "comand4", "comand4")
EndFunc


Если ищете рациональное зерно, то можем для примера взять работу оператора Select или Switch с большим количеством Case. Реализовано это как проверка всех подряд условий до нахождения подходящего. Я считаю что правильное применение массива функций более эффективно (не полностью заменяет, а во многих случаях будет эффективнее)

по моему это и есть оптимальное решение.

Реализовано это как проверка всех подряд условий до нахождения подходящего
Не совсем так, особенностью switch, есть то что он не перебирает все варианты, а сразу переходит на нужный, при наличии такового. За счет этого switch и быстрее оператора if. Да и преимущества массивов проявляется в основном при работе с большими объемами информации, а тут нужно из большого списка выбрать конкретный. Имхо, switch для этого оптимальный...

OffTopic:
Ого скок написали пока набегами писал))
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
beliy [?]
Не совсем так, особенностью switch, есть то что он не перебирает все варианты, а сразу переходит на нужный, при наличии такового. За счет этого switch и быстрее оператора if.
это не так. я не уверен по поводу switch, но где-то проскакивала инфа, что таки наоборот. но в чем я точно уверен, так это в том, что if после нахождения ветки с истинным значением проверочного условия не проверяет остальные.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Kaster [?]
это не так. я не уверен по поводу switch, но где-то проскакивала инфа, что таки наоборот. но в чем я точно уверен, так это в том, что if после нахождения ветки с истинным значением проверочного условия не проверяет остальные.

Проверяется довольно просто:

Код:
$sTest = 2

Switch $sTest
	Case _0()
		
	Case _1()
		
	Case _2()
		MsgBox(64, 'Title', 2)
	Case _3()
		
EndSwitch

Func _0()
	ConsoleWrite('0 Checked' & @LF)
	Return 0
EndFunc

Func _1()
	ConsoleWrite('1 Checked' & @LF)
	Return 1
EndFunc

Func _2()
	ConsoleWrite('2 Checked' & @LF)
	Return 2
EndFunc

Func _3()
	ConsoleWrite('3 Checked' & @LF)
	Return 3
EndFunc


здесь видно, что проверяются все условия, до найденного, далее не проверяется, в принципе тоже самое что и с If...Else.
 

AZJIO

Меценат
Меценат
Сообщения
2,878
Репутация
1,194
Kaster
но где-то проскакивала инфа, что таки наоборот
switch работает быстрее, я специально тестировал и даже добавил это в справку в дополнительном разделе "If ... Then Обучение"

If ... Then - сравнивает каждый раз независимые эелеметы, а switch имеет одно постоянное значение, это и является критерием скорости.
 
Автор
C2H5OH

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
по моему это и есть оптимальное решение.

Нет.
По-моему, оптимальное решение это вместо
Код:
Switch $value
           Case 1
           _func1()
           Case 2
           _func2()
           Case 3
           _func3()
           ...
           Case 330
           _func330()
   EndSwitch


использовать
Код:
_func[$value]()


Опять же отмечу что это не отказ от использования Switch, но в ряде задач массив функций был бы эффективнее.
 
Автор
C2H5OH

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
Чисто теоретически - смотри мой предыдущий пост.

Практически:
сейчас это не конкретно. Это мысль, которая периодически приходит.
 

erlik

Продвинутый
Сообщения
317
Репутация
84
Так как тема созданная C2H5OH мне близка - в свое время использовал массивы функций очень часто - на Lua (стоит ли объяснять, что это один из часто используемых скриптовых языков для надстроек игровых движков? ;)), приведу некоторый пример функционала массива функций. Ниже - мой код для игры S.T.A.L.K.E.R, (раньше очень много "модил" для нее :smile:). Синтаксис Lua бейсикоподрбный, поэтому несложен для понимания.

Код создает динамический массив функций-таймеров (добавить новую функцию можно было в любой момент), для вызова в определенное время нужной функции из нужного игрового модуля\файла. Позволял избавиться от длиннющей (число функций могло переваливать за сотню) цепочки if ... then
namefunc()
end .
Код:
--// таблица для хранения функций и переменных
local tTimeCallback={[1]={},[2]={}}

--// формируем таблицу
--[[аргументы:
sName -имя функции, которую нужно вызвать по таймеру - пишется так: "имя_файла.имя_функции" - кавычки обязательны
sType - тип времени для таймера:  'y' -годы, 'm' - месяцы, 'd' - день, 'h'- часы, 'min' - минуты, 's'- секунды, 'ms' - миллисекунды
bGame -необязательный параметр - использовать реальное или игровое время.
    ПО умолчанию скрипт использует реальное время и передавать в bGame ничего не требуется, 
    при указании данного параметра как true скрипт будет назначать таймеру игровое время. 
	Есть возможность передавать время как строку вида "02/01/2012 12:12:12"  -- 
	то есть именно в указанное здесь время таймер вызовет нужную функцию. 
В этом случае передавать аргументы sType, bGame не требуется. 
]]

function StartTime(sName, iTime, sType, bGame)
if type(iTime)=="number" then
tTimeCallback[1][sName] =  AddTime(sType, iTime, bGame)
elseif type(iTime)=="string" then 
tTimeCallback[1][sName] =  iTime
end
tTimeCallback[2][sName] = function() if tTimeCallback[1][sName] and tTimeCallback[1][sName] ==GetStringFullTime() then
        local module, file = ParseString(sName)
		_G[module][file]() -- если true вызываем нужную нам функцию
        tTimeCallback[1][sName] = nil
        tTimeCallback[2][sName] = nil
        end
    end [[это безымянная функция проверяющая условие - параметры функции передаются в момент вызова StartTime(аргументы) из нужного участка кода - функция записывается в массив и постоянно вызывается ]]
end

-- а вот это вызывалось определенно число раз в секунду 
function CallF()
GetStringFullTime()
for k, v in pairs(tTimeCallback[2]) do 
    v() -- а вот здесь мы перебираем наш массив таймеров и вызываем все функции из массива подряд
   end
end

PS: Так что я двумя руками за расширение возможностей массивов в AutoiT. В lua массивы могут хранить абсолютно любой тип данных - и это его очень большой плюс.
 
Верх