Я люблю Lua. I love Lua.

Итераторы

Posted in Uncategorized by ilovelua on Август 29, 2013

После того, как написал несколько раз такой код:

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

Advertisements

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s

%d такие блоггеры, как: