Я много работал с Lua в последние несколько месяцев, и мне действительно нравится большинство функций, но я все еще упускаю кое-что из них:
- Почему нет
continue
? - Какие есть обходные пути для этого?
loops
lua
language-design
Дант
источник
источник
goto
инструкцию, которую можно использовать для реализации continue. См. Ответы ниже.Ответы:
В Lua 5.2 лучший обходной путь - использовать goto:
-- prints odd numbers in [|1,10|] for i=1,10 do if i % 2 == 0 then goto continue end print(i) ::continue:: end
Это поддерживается в LuaJIT с версии 2.0.1.
источник
continue
день.goto
Замена не выглядит очень красиво и нуждается в большем количестве линий. Кроме того, не было бы проблем, если бы у вас было несколько циклов, выполняющих это в одной функции, оба с::continue::
? Придумывать название для каждого цикла - не самое приличное занятие.То, как язык управляет лексической областью, создает проблемы с включением как
goto
иcontinue
. Например,local a=0 repeat if f() then a=1 --change outer a end local a=f() -- inner a until a==0 -- test inner a
Объявление
local a
внутри тела цикла маскирует внешнюю переменную с именемa
, а область действия этой локальной расширяется по условиюuntil
оператора, поэтому условие проверяет самое внутреннееa
.Если бы он
continue
существовал, его нужно было бы ограничить семантически, чтобы он был действительным только после того, как все переменные, используемые в условии, попали в область видимости. Это сложное условие для документирования для пользователя и выполнения компилятором. Обсуждались различные предложения по этой проблеме, включая простой ответ о запретеcontinue
с помощьюrepeat ... until
стиля цикла. Пока ни у одного из них не было достаточно убедительного варианта использования, чтобы включить их в язык.Обычно обходной путь заключается в том, чтобы инвертировать условие, которое могло бы вызвать
continue
выполнение, и собрать остальную часть тела цикла при этом условии. Итак, следующий цикл-- not valid Lua 5.1 (or 5.2) for k,v in pairs(t) do if isstring(k) then continue end -- do something to t[k] when k is not a string end
можно было бы написать
-- valid Lua 5.1 (or 5.2) for k,v in pairs(t) do if not isstring(k) then -- do something to t[k] when k is not a string end end
Это достаточно ясно и обычно не является обузой, если у вас нет серии сложных отбраковок, которые управляют работой цикла.
источник
until...
.goto
в Lua 5.2. Естественно,goto
есть такая же проблема. В конце концов они решили, что независимо от затрат времени выполнения и / или генерации кода для защиты от него, стоит преимущества гибкости,goto
которую можно использовать для эмуляции как наcontinue
нескольких уровнях, так и на нескольких уровняхbreak
. Чтобы получить подробности, вам придется поискать в архивах списков Lua соответствующие темы. Поскольку они действительно представилиgoto
, это, очевидно, не было непреодолимым.local
является директивой только для компилятора - не имеет значения, какие инструкции выполняются междуlocal
и использованием переменных - вам не нужно ничего менять в компиляторе, чтобы поддерживать такое же поведение области видимости. Да, это может быть не так очевидно и требует дополнительной документации, но, повторюсь еще раз, это требует НУЛЕВЫХ изменений в компиляторе.repeat do break end until true
пример в моем ответе уже генерирует точно такой же байт-код, что и компилятор с continue, с той лишь разницей, чтоcontinue
вам не понадобится уродливый дополнительный синтаксис для его использования.do{int i=0;}while (i == 0);
сбой или в C ++:do int i=0;while (i==0);
также сбой («не был объявлен в этой области»). К сожалению, слишком поздно менять это сейчас в Lua.Вы можете дополнительно обернуть тело цикла,
repeat until true
а затем использоватьdo break end
внутри для эффекта continue. Естественно, вам нужно будет установить дополнительные флаги, если вы также намереваетесь действительноbreak
выйти из цикла.Это будет повторяться 5 раз, каждый раз печатая 1, 2 и 3.
for idx = 1, 5 do repeat print(1) print(2) print(3) do break end -- goes to next iteration of for print(4) print(5) until true end
Эта конструкция даже переводится в буквальный код операции
JMP
в байт- код Lua!$ luac -l continue.lua main <continue.lua:0,0> (22 instructions, 88 bytes at 0x23c9530) 0+ params, 6 slots, 0 upvalues, 4 locals, 6 constants, 0 functions 1 [1] LOADK 0 -1 ; 1 2 [1] LOADK 1 -2 ; 3 3 [1] LOADK 2 -1 ; 1 4 [1] FORPREP 0 16 ; to 21 5 [3] GETGLOBAL 4 -3 ; print 6 [3] LOADK 5 -1 ; 1 7 [3] CALL 4 2 1 8 [4] GETGLOBAL 4 -3 ; print 9 [4] LOADK 5 -4 ; 2 10 [4] CALL 4 2 1 11 [5] GETGLOBAL 4 -3 ; print 12 [5] LOADK 5 -2 ; 3 13 [5] CALL 4 2 1 14 [6] JMP 6 ; to 21 -- Here it is! If you remove do break end from code, result will only differ by this single line. 15 [7] GETGLOBAL 4 -3 ; print 16 [7] LOADK 5 -5 ; 4 17 [7] CALL 4 2 1 18 [8] GETGLOBAL 4 -3 ; print 19 [8] LOADK 5 -6 ; 5 20 [8] CALL 4 2 1 21 [1] FORLOOP 0 -17 ; to 5 22 [10] RETURN 0 1
источник
luac
результаты на SO! Желаем заслуженного голоса :)Первая часть ответа в FAQ , как закланного указывал.
Что касается обходного пути, вы можете обернуть тело цикла функцией и на
return
раннем этапе, например-- Print the odd numbers from 1 to 99 for a = 1, 99 do (function() if a % 2 == 0 then return end print(a) end)() end
Или, если вы хотите и того,
break
и другогоcontinue
, попросите локальную функцию выполнить тест, напримерlocal a = 1 while (function() if a > 99 then return false; -- break end if a % 2 == 0 then return true; -- continue end print(a) return true; -- continue end)() do a = a + 1 end
источник
collectgarbage("count")
даже после ваших простых 100 попыток, и тогда мы поговорим. Такая «преждевременная» оптимизация спасла один высоконагруженный проект от перезагрузки каждую минуту на прошлой неделе.Прямо от дизайнера Lua :
источник
continue
Lua, извините».Я никогда раньше не использовал Lua, но я погуглил и придумал следующее:
http://www.luafaq.org/
Проверьте вопрос 1.26 .
источник
Мы можем добиться этого, как показано ниже, он пропустит четные числа
local len = 5 for i = 1, len do repeat if i%2 == 0 then break end print(" i = "..i) break until true end
O / P:
i = 1 i = 3 i = 5
источник
Мы сталкивались с этим сценарием много раз, и мы просто используем флаг для имитации продолжения. Мы также стараемся избегать использования операторов goto.
Пример: код намеревается распечатать операторы от i = 1 до i = 10, кроме i = 3. Вдобавок он также печатает «начало цикла», «конец цикла», «если начало» и «если конец» для имитации других вложенных операторов, существующих в вашем коде.
size = 10 for i=1, size do print("loop start") if whatever then print("if start") if (i == 3) then print("i is 3") --continue end print(j) print("if end") end print("loop end") end
достигается заключением всех оставшихся операторов до конца цикла с тестовым флагом.
size = 10 for i=1, size do print("loop start") local continue = false; -- initialize flag at the start of the loop if whatever then print("if start") if (i == 3) then print("i is 3") continue = true end if continue==false then -- test flag print(j) print("if end") end end if (continue==false) then -- test flag print("loop end") end end
Я не говорю, что это лучший подход, но он отлично работает для нас.
источник
Lua - это облегченный язык сценариев, который нужно сделать как можно меньше. Например, многие унарные операции, такие как приращение до / после, недоступны.
Вместо продолжения вы можете использовать goto как
arr = {1,2,3,45,6,7,8} for key,val in ipairs(arr) do if val > 6 then goto skip_to_next end # perform some calculation ::skip_to_next:: end
источник
Опять же, при инвертировании вы можете просто использовать следующий код:
for k,v in pairs(t) do if not isstring(k) then -- do something to t[k] when k is not a string end
источник
Почему нет продолжения?
Потому что в этом нет необходимости¹. Очень мало ситуаций, когда это может понадобиться разработчику.
A) Когда у вас очень простой цикл, скажем, с 1 или 2 строками, вы можете просто изменить условие цикла, и он все еще будет хорошо читаемым.
Б) Когда вы пишете простой процедурный код (он же, как мы писали код в прошлом веке), вы также должны применять структурированное программирование (иначе, как мы писали лучший код в прошлом веке).
C) Если вы пишете объектно-ориентированный код, тело вашего цикла должно состоять не более чем из одного или двух вызовов методов, если только это не может быть выражено в одно- или двухстрочном формате (в этом случае см. A)
D) Если вы пишете функциональный код, просто верните простой хвостовой вызов для следующей итерации.
Единственный случай, когда вы захотите использовать
continue
ключевое слово, - это если вы хотите закодировать Lua как python, а это не так. ²Какие есть обходные пути для этого?
Если не применяется пункт A), и в этом случае нет необходимости в каких-либо обходных путях, вы должны выполнять структурированное, объектно-ориентированное или функциональное программирование. Это парадигмы, для которых был создан Lua, поэтому вам придется бороться с языком, если вы изо всех сил стараетесь избегать их шаблонов.
Некоторые пояснения:
¹ Lua - очень минималистичный язык. Он пытается иметь как можно меньше функций, и
continue
утверждение в этом смысле не является важной функцией.Я думаю, эта философия минимализма хорошо отражена Роберто Иерусалимши в этом интервью 2019 года :
² Похоже, что большое количество программистов приходят в Lua с других языков, потому что какая бы программа они ни пытались написать сценарий, случайно использует ее, и многие из них, похоже, не хотят писать ничего, кроме своего языка choice, что приводит к множеству вопросов, таких как «Почему в Lua нет функции X?»
Мац описал похожую ситуацию с Руби в недавнем интервью :
³ Есть несколько способов обойти это; некоторые пользователи предложили использовать
goto
, что в большинстве случаев является достаточно хорошим приближением, но очень быстро становится очень уродливым и полностью ломается из-за вложенных циклов. Использованиеgoto
s также подвергает вас опасности получить копию SICP, брошенную вам всякий раз, когда вы показываете свой код кому-либо еще.источник
continue
может быть удобной функцией, но в этом нет необходимости . Многие люди прекрасно используют Lua и без него, так что на самом деле нет никаких оснований полагать, что это что-то еще, кроме изящной функции, которая не является существенной для любого языка программирования.