답변:
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
버전 2.0.1 이후 LuaJIT에서 지원됩니다.
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
루프 스타일. 지금까지 아무도 언어에 포함시킬만큼 충분한 유스 케이스가 없었습니다.
해결 방법은 일반적으로 a 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에 도입하기 전에 Lua 커뮤니티에서 이에 대해 많은 논의가있었습니다 . 당연히 goto
같은 문제가 있습니다. 그들은 결국 런타임 및 / 또는 코드 생성 비용을 막기 위해 무엇이든 멀티 레벨과 goto
에뮬레이션에 모두 사용할 수 있는 유연성 을 갖는 이점이 있다고 판단했습니다 . 세부 정보를 얻으려면 관련 스레드에 대한 Lua 목록 아카이브 를 검색해야합니다 . 그들이 도입했기 때문에 분명히 극복 할 수 없었습니다. continue
break
goto
local
컴파일러 전용 지시문입니다-런타임 인스트루먼트 local
와 변수 사용법 사이에 상관 이 없습니다. 동일한 범위 지정 동작을 유지하기 위해 컴파일러에서 아무것도 변경할 필요가 없습니다. 그렇습니다. 이것은 분명하지 않으며 추가 문서가 필요하지만 다시 반복하려면 컴파일러에서 ZERO 변경이 필요합니다. repeat do break end until true
내 대답의 예는 이미 컴파일러가 계속하는 것과 동일한 바이트 코드를 생성 하지만 유일한 차이점은 continue
사용하기 위해 추악한 추가 구문이 필요하지 않다는 것입니다.
do{int i=0;}while (i == 0);
실패 또는 C ++ 의 동등도 고려하십시오 do int i=0;while (i==0);
( "이 범위에서 선언되지 않았습니다"). 불행히도 Lua에서 지금 변경하기에는 너무 늦었습니다.
루프 바디를 추가로 포장 repeat until true
한 다음 do break end
계속 을 위해 내부를 사용할 수 있습니다 . 물론 실제로 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
는 루아 바이트 코드 에서 문자 그대로 하나의 opcode 로 변환됩니다 !
$ 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
출력을 제공하는 것을 보게 되어 기쁩니다! 잘 받아
"계속"에 대한 우리의 주요 관심사는 (계속해서) "계속"만큼 중요하거나이를 대체 할 수있는 몇 가지 다른 제어 구조가 있다는 것입니다. (예를 들어, [Java에서와 같이] 레이블 또는보다 일반적인 레이블로 분리하십시오.) "계속"은 더 많은 언어로 존재한다는 점을 제외하고 다른 제어 구조 메커니즘보다 더 특별 해 보이지 않습니다. (Perl에는 실제로 "next"와 "redo"라는 두 개의 "continue"문이 있습니다. 둘 다 유용합니다.)
continue
루아에 빠뜨리는 것을 잊어 버렸습니다 ." 보다 더 합리적으로 들리지 않았습니다 .
첫 번째 부분은에 대한 답변 자주 묻는 질문 으로 죽임을 지적 아웃.
해결 방법은 루프 본문을 함수로 감싸서 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 번 시도 후에도 가면 우리가 이야기 할 것입니다. 이러한 "미숙 한"최적화는 지난 주에 1 분마다 하나의 하이로드 프로젝트가 재부팅되는 것을 막았습니다.
나는 전에 Lua를 사용한 적이 없지만, 구글 검색하여 이것을 생각해 냈습니다.
질문 1.26을 확인하십시오 .
이것은 일반적인 불만입니다. Lua의 저자는 계속이 여러 가지 새로운 제어 흐름 메커니즘 중 하나 일 뿐이라고 생각했습니다 (반복 / 정지의 범위 규칙으로 작동 할 수 없다는 사실이 보조 요인이었습니다).
Lua 5.2에는 동일한 작업을 수행하는 데 쉽게 사용할 수있는 goto 문이 있습니다.
이 시나리오는 여러 번 발생했으며 플래그를 사용하여 계속을 시뮬레이션합니다. 우리는 goto 구문도 사용하지 않도록 노력합니다.
예 : 코드는 i = 3을 제외하고 i = 1에서 i = 10까지 명령문을 인쇄하려고합니다. 또한 "loop start", loop end ","if start "및"if end "를 인쇄하여 코드에 존재하는 다른 중첩 된 명령문을 시뮬레이션합니다.
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 라이너와 같이 매우 간단한 루프가 있으면 루프 조건을 돌리면 여전히 읽을 수 있습니다.
B) 간단한 절차 적 코드 (일명 지난 세기에 코드를 작성한 방법)를 작성할 때 구조적 프로그래밍 (일명 지난 세기에 더 나은 코드를 작성한 방법)을 적용해야합니다.
C) 객체 지향 코드를 작성하는 경우 루프 본문은 하나 또는 두 개의 라이너로 표현할 수없는 경우 하나 또는 두 개의 메소드 호출로 구성되어야합니다 (이 경우 A 참조).
D) 기능 코드를 작성하는 경우 다음 반복에 대한 일반 꼬리 호출을 반환하십시오.
continue
키워드 를 사용하려는 유일한 경우 는 파이썬처럼 Lua를 코딩하고 싶을 때뿐입니다 .²
A)가 적용되지 않는 한, 어떤 경우에도 해결 방법이 필요하지 않으면 구조적, 객체 지향적 또는 기능적 프로그래밍을 수행해야합니다. 이것들은 루아가 만든 패러다임입니다. 따라서 패턴을 피하기 위해 벗어나면 언어에 맞서 싸울 것입니다 .³
몇 가지 설명 :
¹ 루아는 매우 최소한의 언어입니다. 가능한 한 적은 수의 기능을 사용하려고 시도 continue
하며 그 의미에서 진술은 필수적인 기능이 아닙니다.
이 미니멀리즘 철학은 2019 년 인터뷰 에서 Roberto Ierusalimschy 가 잘 포착 한 것 같습니다.
우리는 최종 결론이 대부분의 사람들을 만족시키지 않을 것이며 모든 사람이 원하는 모든 옵션을 넣지 않을 것이라는 것을 이해하므로 아무것도 넣지 않습니다. 결국, 엄격 모드는 합리적인 절충안입니다.
² 스크립트를 작성하려는 모든 프로그램에서이를 사용하기 때문에 많은 언어가 다른 언어에서 루아로 온 많은 프로그래머가있는 것 같습니다. "루아에 X 기능이없는 이유는 무엇입니까?"
Matz 는 최근 인터뷰 에서 Ruby와 비슷한 상황을 설명했습니다 .
가장 인기있는 질문은 "저는 언어 X 커뮤니티에서 왔으며 언어 X에서 루비로 기능을 소개 할 수 없습니까?"라는 것입니다. 그리고 우리가 다른 언어 디자인과 다른 언어 개발 정책을 가지고 있기 때문에 이러한 요청에 대한 나의 일반적인 대답은…“아니요.
³이 문제를 해결하기위한 몇 가지 방법이 있습니다. 일부 사용자는을 사용하도록 제안 goto
했는데, 이는 대부분의 경우에 충분한 근사치이지만 매우 빠르게 추악 해지고 중첩 루프로 완전히 중단됩니다. 또한 goto
s를 사용하면 다른 사람에게 코드를 보여줄 때마다 SICP 사본이 발생할 위험이 있습니다.
continue
편리한 기능 일 수도 있지만 반드시 필요한 것은 아닙니다 . 많은 사람들이 루아를 사용하지 않고 잘 사용하므로 프로그래밍 언어에 필수적이지 않은 깔끔한 기능 이외의 다른 사례는 없습니다.
goto
계속 구현하는 데 사용할 수 있는 진술을 받았습니다 . 아래 답변을 참조하십시오.