Тема: Советы
Обратился ко мне начинающий луа-программист с куском не рабочего кода.
Код написан вот в таком стиле, с кучей проверок, что само по себе не плохо, но как!
function fn(ds, signal)
if ds ~= nil then
local index = ds:Size()
local O, H, L, C = ds:O(index), ds:O(index), ds:O(index), ds:O(index)
if O ~= 0 and H ~= 0 and L ~= 0 and C ~= 0 then
if signal == 0 then
return (O + H + L + C)/4
elseif signa > 0 then
if O >= C then
return O
else
return C
end
else
if O >= C then
return C
else
return O
end
end
else
return 0
end
else
return 0
end
end
Уровень вложенности блоков зашкаливает!
Читать такой код совсем не было желания, а на поиск оЧепятки или логической ошибки могло уйти много времени. Быстрее написать заново.
Так как это не первое подобное обращение, решил написать здесь пару советов.
1. При использовании документированных функций, обратите внимание на возвращаемый результат, в случае ошибки.
2. При вызове собственной функции, проверяйте передаваемые параметры до! вызова функции. Если какой то параметр не проходит проверку, то в вызове функции смысла нет.
3. Соблюдайте уровень вложенности логических блоков, если он > 3, то код не читабельный, за поиск ошибки с вас попросят больше денег (время - деньги). Если по логике не выходит вложиться в эти рамки, то напишите дополнительную функцию и уберите лишнее ветвление в нее, тем самым вы понизите уровень вложенности.
4. Без нужды не используйте функции приведения типов - tostring, tonumber, это затратные по времени функции. Если сомневаетесь в типе данных, которые получаете из таблиц квик-а, проверьте их: message("price_type = type(item.price), 2)
5. Перед вычислениями нужно обработать все исключения, т.е. если для дальнейших расчетов один из параметров/переменных может привести к ошибке вычисления, то дальше считать нет смысла.
Вот так, примерно:
local function fn(ds, signal)
-- signal по умолчанию число [-1; 1], его проверять не будем
-- ds источник данных графика, на nil проверяется до вызова функции fn
local index = ds:Size()
-- вот эту проверку можно тоже сделать до вызова этой функции
if index == 0 then reurn 0 end
local O, H, L, C = ds:O(index), ds:O(index), ds:O(index), ds:O(index)
-- и эту проверку тоже, вдруг где-то еще понадобятся O, H, L, C
if O == 0 or H == 0 or L == 0 or C == 0 then return 0 end
-- все, исключения обработали, теперь к делу
if signal == 0 then
-- вот тут второй уровень вложенности
return (O + H + L + C)/4
end
if signal > 0 then
if O >= C then
-- это уже третий уровень вложенности, еще читабельно
return O
else
return C
end
end
-- убираем ветвление else, т.к. если до сюда дошло, то уже else (signal < 0)
if O >= C then
return C
else
return O
end
end
6. Доступ к глобальным луа-переменным медленнее, чем к локальным. Для ускорения выполнения алгоритма многие советуют вначале скрипта делать так:
local os_time = os.time
local floor = math.floor
local tm = os_time() -- это будет быстрее, чем вызвать функцию time() из глобальной таблицы os
local a = floor(3.14) -- и так быстрее
чтобы не генерировать ошибки в дальнейшем, при копирования кода из одного скрипта в другой, можно и нужно делать так:
local os = os
local math = math
local tm = os.time()
local a = math.floor(3.14)
это тоже быстро и будет работать, даже если вы где-то забудете объявить
local math = math
на вот такой объявление совет не распространяется тут никак не ошибешься при копировании.
local tonubber, tostring = tonubber, tostring
а подсветка синтаксиса останется.
В общем, успехов в начинаниях, и дополняйте раздел.