이것이 goto 진술을 정당화합니까?


15

나는 두 번째 전에이 질문을 보았고 거기에서 몇 가지 자료를 가져 왔습니다 . 'break n'구문의 이름이 있습니까?

이것은 사람들이 프로그램을 이중 중첩 for 루프에서 벗어나도록 지시 해야하는 복잡한 방법으로 보입니다.

for (i = 0; i < 10; i++) {
    bool broken = false;
    for (j = 10; j > 0; j--) {
        if (j == i) {
            broken = true;
            break;
        }
    }
    if (broken)
        break;
}

나는 goto 선언이 악마라고 말하는 교과서들을 알고 있으며, 나는 그것들을 전혀 좋아하지 않지만 규칙에 대한 예외를 정당화합니까?

n-nested for 루프를 다루는 답변을 찾고 있습니다.

참고 : 예, 아니요 또는 그 사이의 어딘가에 상관없이 완전히 가까운 대답은 환영 하지 않습니다 . 특히 대답이 '아니요'인 경우 왜 합법적 인 이유를 제시해야합니까 (어쨌든 Stack Exchange 규정에서 너무 멀지 않음).


2
내부 루프 조건을 작성할 수 있다면 명령문이 for (j = 10; j > 0 && !broken; j--)필요하지 않습니다 break;. broken외부 루프가 시작되기 전에 의 선언을 이동하면 s가 필요 하지for (i = 0; i < 10 && !broken; i++) 않다고 생각할 수 있습니다 . break;
FrustratedWithFormsDesigner

8
예를 들어 C #에서 온 것으로 주어진 경우 goto: goto (C # Reference) - "goto 문은 깊이 중첩 된 루프를 벗어나는 데 유용합니다."

세상에, C #에 goto 문이 있다는 것을 몰랐어요! StackExchange에서 배우는 것들. (goto statement 기능을 마지막으로 원했을 때 기억이 나지 않습니다.)
John Wu

6
IMHO 그것은 정말로 "프로그램 종교"와 현재 달의 위상에 달려 있습니다. 나 (그리고 대부분의 사람들)에게 루프가 다소 작 으면 goto를 사용하여 깊은 둥지에서 나가는 것이 좋으며, 대안은 루프 조건이 깨지기 위해 도입 된 bool 변수를 불필요한 검사로 보는 것입니다. 이것은 몸을 반쯤 뚫고 싶을 때 또는 가장 안쪽 루프 후에 부울을 확인 해야하는 코드가있을 때 더 그렇습니다.
PlasmaHH

1
@JohnWu goto는 실제로 C # 스위치에서 첫 번째 사례 내에서 코드를 실행 한 후 다른 사례로 넘어갈 수 있어야합니다. 그래도 내가 사용한 유일한 사례입니다.
Dan Lyons 2018

답변:


33

루프에 대해 열악한 조건식을 선택 하면 go-to 문이 분명히 필요합니다 .

외부 루프를 최대한 길게 유지 i < 10하고 가장 안쪽 루프를 계속 유지하고 싶다고 설명합니다 j > 0.

그러나 실제로는 그것이 원하는 것이 아닙니다. 루프에 평가하려는 실제 조건을 루프에 알려주지 않고 break 또는 goto를 사용하여 해결하려고합니다.

루프에서로 시작하려는 진정한 의도를 말하면 중단하거나 갈 필요가 없습니다.

bool alsoThis = true;
for (i = 0; i < 10 && alsoThis; i++)
{    
    for (j = 10; j > 0 && alsoThis; j--)
    {
        if (j == i)
        {
            alsoThis = false;
        }
    }
}

다른 답변에 대한 내 의견을 참조하십시오. 원본 코드 i는 외부 루프의 끝에 인쇄 되므로 코드를 100 % 동일하게 보이게하려면 증분을 단락시키는 것이 중요합니다. 나는 당신의 대답에 어떤 것도 잘못되었다고 말하는 것이 아니라, 루프를 즉시 깨는 것이 코드의 중요한 측면 이라는 것을 지적하고 싶었습니다 .
pswg

1
@pswg iOP의 질문에 외부 루프 끝에 코드 인쇄가 표시되지 않습니다 .
Tulains Córdova

OP는 here 에서 내 질문 의 코드를 참조 했지만 그 부분은 생략했습니다. 난 당신을 공감하지 않았습니다, BTW. 루프 조건을 올바르게 선택하는 것과 관련하여 정답입니다.
pswg

3
@pswg 정말 정말로 정말로 goto를 정당화하고 싶다면 하나를 필요로하는 문제를 해결할 수 있습니다. 반면에, 저는 20 년 동안 전문적으로 프로그래밍 해 왔으며 필요한 실제 문제는 하나도 없었습니다. 하나.
Tulains Córdova

1
코드의 목적은 그 goto와 같이 사용되는 것으로 보이는 질문을 낳은 경우에도 유효한 유스 케이스를 제공하지는 않았지만 ( '더 나은 것이있을 것이라고 확신합니다. break(n)') 지원하지 않습니다.
pswg

34

이 경우 코드를 별도의 루틴으로 리팩터링 한 다음 return내부 루프에서 리팩터링 할 수 있습니다. 그것은 외부 루프에서 벗어날 필요성을 무효화합니다.

bool isBroken() {
    for (i = 0; i < 10; i++)
        for (j = 10; j > 0; j--)
            if (j == i) return true;

    return false;
}

2
즉, 네가 보여주는 것은 중첩 루프에서 벗어날 수있는 불필요하게 복잡한 방법이지만, 더 매력적으로 만들지 않는 리팩토링 방법이 있습니다.
Roger

2
참고 사항 : 원래 코드 i에서는 외부 루프가 끝난 후에 인쇄 합니다. i이것이 중요한 가치 라는 것을 실제로 반영하기 위해서는 여기 return true;return false;가 모두 있어야 return i;합니다.
pswg

+1,이 답변을 게시하려고했으며 이것이 승인 된 답변이어야한다고 믿습니다. 이 방법은 중첩 루프 알고리즘의 특정 하위 집합에만 작동하며 코드를 더 깨끗하게 만들지 않기 때문에 허용 된 답변이 수락되었다고 믿을 수 없습니다. 이 답변의 방법은 일반적으로 작동합니다.
Ben Lee

6

아니요, goto필요 하다고 생각하지 않습니다 . 다음과 같이 작성하면

bool broken = false;
saved_i = 0;
for (i = 0; i < 10 && !broken; i++)
{
    broken = false;
    for (j = 10; j > 0 && !broken; j--)
    {
        if (j == i)
        {
            broken = true;
            saved_i = i;
        }
    }
}

&&!broken두 루프에 모두 있으면 두 루프에서 벗어날 수 있습니다 i==j.

나 에게이 접근 방식이 바람직합니다. 루프 조건은 매우 명확 i<10 && !broken합니다.

작업 버전은 여기에서 볼 수 있습니다 : http://rextester.com/KFMH48414

암호:

public static void main(String args[])
{
    int i=0;
    int j=0;
    boolean broken = false;
    for (i = 0; i < 10 && !broken; i++)
    {
        broken = false;
        for (j = 10; j > 0 && !broken; j--)
        {
            if (j == i)
            {
                broken = true;
                System.out.println("loop breaks when i==j=="+i);
            }
        }
    }
    System.out.println(i);
    System.out.println(j);
}

산출:

i == j == 1 일 때 루프 중단
2
0

broken첫 번째 예 에서 전혀 사용하지 않습니까? 내부 루프에서 브레이크를 사용하십시오. 또한 절대적으로 사용해야하는 broken경우 루프 외부에서 선언 해야하는 이유는 무엇입니까? 그냥 선언 안에i 루프. 에 관해서는 while루프, 그것을 사용하지 마십시오. 솔직히 그것이 goto 버전 보다 읽기 쉽지 않다고 생각합니다 .
luiscubal

@ luiscubal : 이름 broken이 붙은 변수 는 break문을 사용하는 것을 좋아하지 않기 때문에 사용됩니다 (스위치 경우 제외). when 모든 루프를 중단하려는 경우 외부 루프 외부에 선언됩니다 i==j. 일반적으로 맞습니다 broken. 가장 바깥 쪽 루프보다 먼저 선언해야합니다.
FrustratedWithFormsDesigner

당신의 업데이트에서, i==2루프의 끝에서. 성공 조건은 증분이 a와 100 % 같아야 증가를 단락시켜야합니다 break 2.
pswg

2
나는 개인적으로 broken = (j == i)if보다는 언어를 선호 하고 언어가 허용하는 경우 깨진 선언을 외부 루프 초기화 안에 넣는 것을 선호합니다 . 이 특정 예제에 대해 이러한 것들을 말하기는 어렵지만 전체 루프는 no-op (아무것도 반환하지 않고 부작용이 없음)이므로 무언가를 수행하면 if 내부에서 수행 할 수 있습니다 (아직도 broken = (j ==i); if broken { something(); }나아지 기는하지만) 개인적으로)
Martijn

@Martijn 내 원래 코드 i에서는 외부 루프가 끝난 후에 인쇄 됩니다. 다시 말해서, 정말로 중요한 유일한 생각은 외부 루프에서 정확히 벗어날 때입니다.
pswg

3

짧은 대답은 "그것은 달려있다"입니다. 코드의 가독성과 이해 가능성에 대해 선택하는 것을 옹호합니다. 이동 경로는 조건을 조정하는 것보다 더 읽기 쉬울 수 있습니다. 또한 상점 / 프로젝트에서 사용되는 지침과 코드베이스의 일관성을 최소한의 놀라움의 원칙으로 고려할 수도 있습니다. 예를 들어 스위치를 나가거나 오류 처리를하는 것은 Linux 커널 코드 기반의 일반적인 관행입니다. 또한 일부 프로그래머는 코드를 읽는 데 문제가 있거나 ( "goto is evil"만트라로 제기되거나 교사가 그렇게 생각하기 때문에 배우지 못했을 수 있음) 일부 사용자는 "심판"할 수도 있습니다.

일반적으로 말하면, 특히 점프가 너무 길지 않은 경우 같은 기능으로 더 나아가는 것이 허용됩니다. 중첩 루프를 떠나는 유스 케이스는 "나쁘지 않은"goto의 알려진 예 중 하나입니다.


2

귀하의 경우 goto는 유혹적으로 보일 정도로 개선되었지만 코드베이스에서 규칙을 사용하는 것에 대한 규칙을 어길 가치가있는 것은 아닙니다.

미래의 검토 자에 대해 생각해보십시오. "그 사람은 나쁜 코더입니까, 아니면 실제로 고토가 가치가있는 경우입니까?"라고 생각해야합니다. 인터넷." goto를 완전히 사용할 수 없을 때 왜 미래의 코더에게 그렇게 할 것입니까?

일반적으로이 사고 방식은 모든 "나쁜"코드에 적용되며 심지어 정의하기까지합니다. 지금 작동하고이 경우에는 좋지만이 코드가 올바른지 확인하기 위해 노력합니다. 해.

즉, 당신은 약간 더 가시적 인 사례 중 하나를 생산했습니다. 당신은 할 수있다:

  • 부울 플래그와 같이 더 복잡한 제어 구조를 사용하여 두 루프를 모두 분리하십시오.
  • 내부 루프를 자체 루틴에 넣으십시오 (아마 이상적)
  • 두 루프를 루틴에 넣고 깨지 않고 반환

이중 루프가 너무 응집력이 없어서 자체 루틴이되어서는 안되는 경우를 만드는 것은 매우 어렵습니다.

그건 그렇고, 내가 본 이것에 대한 가장 좋은 토론은 Steve McConnell의 Code Complete 입니다. 이 문제들을 비판적으로 생각하는 것을 좋아한다면, 그 책의 내용은 엄청나지만 책을 읽거나 읽을 것을 강력히 권합니다.


1
코드를 읽고 이해하는 것은 직업 프로그래머입니다. 코드베이스의 특성이 아니라면 단순한 코드 만이 아닙니다. 이해 된 비용 때문에 고 토스 사용에 대한 일반성 (규칙이 아님)에는 항상 예외가 있습니다. 이익이 비용을 능가 할 때마다 goto를 사용해야합니다. 소프트웨어 엔지니어링의 모든 코딩 결정의 경우와 같습니다.
dietbuddha

1
@dietbuddha는 적절히 고려되어야하는 수용된 소프트웨어 코딩 규약을 위반하는 비용이 있습니다. 이러한 제어 구조가 상황에 적합하더라도 프로그램에 사용되는 제어 구조의 다양성을 증가시키는 비용이 있습니다. 정적 정적 코드 분석에는 비용이 발생합니다. 이것이 여전히 가치가 있다면, 누가 논쟁해야합니까.
djechlin

1

TLD; DR : 구체적으로 아니오, 일반적으로 예

당신이 사용한 특정 예에서 나는 다른 많은 사람들이 지적한 것과 같은 이유로 no라고 말할 것입니다. 코드를 동등하게 좋은 형식으로 쉽게 리팩터링 할 수 있으므로 goto.

일반적으로 금지 규정 goto은 이해의 본질 goto과 사용 비용에 근거한 일반성 입니다. 소프트웨어 엔지니어링의 일부는 구현 결정을 내립니다. 이러한 결정에 대한 정당화는 비용과 이점을 비교함으로써, 그리고 이점이 비용을 능가 할 때마다 구현이 정당화됩니다. 비용과 이익 모두 다른 평가로 인해 논란이 일어납니다.

요점은 a goto가 정당화 되는 경우 항상 예외가 있지만 다른 평가로 인해 일부에만 적용 된다는 것 입니다. 안타깝게도 많은 엔지니어들은 이유를 이해하기 위해 시간을 내기보다는 인터넷에서 기술을 읽기 때문에 의도적으로 무지한 기술을 배제합니다.


goto 명세서에 비용을 추가로 설명하는 기사를 추천 할 수 있습니까?
Thys

-1

나는이 경우가 다음과 같이 쓰여질 수 있기 때문에 예외를 정당화한다고 생각하지 않는다.

def outerLoop(){
    for (i = 0; i < 10; i++) {
        if( broken?(i) )
          return; // broken
    }
}

def broken?(i){
   for (j = 10; j > 0; j--) {
        if (j == i) {
            return true; // broken
        }
   }
   return false; // not broken
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.