Итераторы
После того, как написал несколько раз такой код:
function(command, ...) ... local combos = command.combos if combos then local deviceCombos = combos[deviceName] if deviceCombos then for i, combo in ipairs(deviceCombos) do -- что-то сделать с combo ... end end end ... end
мне стало понятно, что нужно придумать что-нибудь поизящнее, чем эти двойные проверки. И тут я вспомнил про итераторы! Programming in Lua говорит нам, что итератором может быть функция, которая при каждом вызове возвращает следующий элемент коллекции. Поскольку deviceCombos это массив, а мне при переборе индекс элемента не нужен, то задача упрощается:
function commandCombos(command, deviceName) local pos = 0 local combos local deviceCombos if command then combos = command.combos if combos then deviceCombos = combos[deviceName] end end return function() if deviceCombos then pos = pos + 1 return deviceCombos[pos] end end end
Обратите внимание, что переменная pos — это upvalue.
Теперь проверим получившуюся функцию:
local commandNil = nil local commandNoCombos = {} local commandEmptyCombos = { combos = {}, } local command = { combos = { mouse = { {key = 'MOUSE1', action = 1}, {key = 'MOUSE2', action = 2}, }, keyboard = { {key = 'A', action = 11}, {key = 'B', action = 22}, }, } } for combo in commandCombos(commandNil) do assert(false) end for combo in commandCombos(commandNoCombos) do assert(false) end for combo in commandCombos(commandNoCombos) do assert(false) end for combo in commandCombos(commandEmptyCombos) do assert(false) end for combo in commandCombos(command, 'mouse') do print('~~~mouse', combo.key, combo.action) end for combo in commandCombos(command, 'keyboard') do print('~~~keyboard', combo.key, combo.action) end
На выходе ожидаемо получаем:
~~~mouse MOUSE1 1
~~~mouse MOUSE2 2
~~~keyboard A 11
~~~keyboard B 22
leave a comment