명백하고 관련이있는 경우에 goto가 나쁜 점은 무엇입니까?


40

나는 항상 그것이 goto나쁜 것으로 알고있다. 어딘가에 지하실에 갇혀 있지 않다. 그러나 오늘 코드 예제를 보았는데 사용하기에 완벽하다 goto.

IP 목록에 있는지 확인한 다음 코드를 진행하고 그렇지 않으면 예외를 처리해야하는 IP가 있습니다.

<?php

$ip = '192.168.1.5';
$ips = [
    '192.168.1.3',
    '192.168.1.4',
    '192.168.1.5',
];

foreach ($ips as $i) {
    if ($ip === $i) {
        goto allowed;
    }
}

throw new Exception('Not allowed');

allowed:

...

내가 사용하지 않으면 goto다음과 같은 변수를 사용해야합니다

$allowed = false;

foreach ($ips as $i) {
    if ($ip === $i) {
        $allowed = true;
        break;
    }
}

if (!$allowed) {
    throw new Exception('Not allowed');
}

내 질문은 그것이 goto명백하고 imo 관련 사건에 사용될 때 무엇이 나쁜 것입니까?


의견은 긴 토론을위한 것이 아닙니다. 이 대화는 채팅 으로 이동 되었습니다 .
maple_shaft

답변:


120

GOTO 자체는 즉각적인 문제가 아니라 사람들이 구현하는 암시 적 상태 시스템입니다. 귀하의 경우 IP 주소가 허용 된 주소 목록에 있는지 확인하는 코드가 필요합니다.

if (!contains($ips, $ip)) throw new Exception('Not allowed');

코드에서 조건을 확인하려고합니다. 이 검사를 구현하는 알고리즘은 여기서 중요하지 않습니다. 주 프로그램의 정신 공간에서 검사는 원 자성입니다. 그렇게되어야합니다.

그러나 검사를 수행하는 코드를 기본 프로그램에 넣으면 손실됩니다. 변경 가능한 상태를 명시 적으로 소개하십시오.

$list_contains_ip = undef;        # STATE: we don't know yet

foreach ($ips as $i) {
  if ($ip === $i) {
      $list_contains_ip = true;   # STATE: positive
      break;
  }
                                  # STATE: we still don't know yet, huh?                                                          
                                  # Well, then...
  $list_contains_ip = false;      # STATE: negative
}

if (!$list_contains_ip) {
  throw new Exception('Not allowed');
}

$list_contains_ip유일한 상태 변수는 어디 입니까?

                             # STATE: unknown
foreach ($ips as $i) {       # What are we checking here anyway?
  if ($ip === $i) {
    goto allowed;            # STATE: positive
  }
                             # STATE: unknown
}
                             # guess this means STATE: negative
throw new Exception('Not allowed');

allowed:                     # Guess we jumped over the trap door

보시다시피, GOTO 구문에는 선언되지 않은 상태 변수가 있습니다. 그것은 그 자체로는 문제가 아니지만, 이러한 상태 변수는 자갈과 같습니다. 코드는 동일하게 유지되지 않습니다. 다음 달에는 개인 주소와 공개 주소를 구분하라는 메시지가 표시됩니다. 그 다음 달에는 코드가 IP 범위를 지원해야합니다. 내년에는 누군가가 IPv6 주소를 지원하도록 요청할 것입니다. 곧 코드는 다음과 같습니다.

if ($ip =~ /:/) goto IP_V6;
if ($ip =~ /\//) goto IP_RANGE;
if ($ip =~ /^10\./) goto IP_IS_PRIVATE;

foreach ($ips as $i) { ... }

IP_IS_PRIVATE:
   foreach ($ip_priv as $i) { ... }

IP_V6:
   foreach ($ipv6 as $i) { ... }

IP_RANGE:
   # i don't even want to know how you'd implement that

ALLOWED:
   # Wait, is this code even correct?
   # There seems to be a bug in here.

그리고 그 코드를 디버깅해야하는 사람은 당신과 당신의 아이들을 저주 할 것입니다.

Dijkstra는 다음과 같이 말합니다.

go to 명령문을 제한없이 사용하면 프로세스 진행 상황을 설명 할 의미있는 좌표 세트를 찾기가 매우 어려워집니다.

그래서 GOTO는 해로운 것으로 간주됩니다.


22
$list_contains_ip = false;말은 잘못
놓인

1
자갈로 가득 찬 가방은 쉽지만, 보관하기 편리한 가방이 있습니다. : p
whatsisname

13
@ Bergi : 당신이 맞아요. 그것은 이런 것들을 망가 뜨리는 것이 얼마나 쉬운지를 보여줍니다.
wallenborn

6
@whatsisname 그 가방은 그것들을 담기위한 함수 / 클래스 / 패키지라고합니다. gotos를 사용하는 것은 저글링과 가방을 버리는 것과 같습니다.
팔코

5
나는 Dijkstra의 인용문을 좋아하지만, 그런 식으로 들리지는 않았지만 정말 좋은 지적입니다. 거의 위에서 아래로 흐르는 흐름을 갖는 대신 갑자기 페이지 전체에 무작위로 뛸 수있는 무언가가 있습니다. 간결하게 말하면 꽤 인상적입니다.
Bill K

41

에 대한 합법적 인 사용 사례가 GOTO있습니다. 예를 들어 C에서의 오류 처리 및 정리 또는 일부 형태의 상태 머신을 구현합니다. 그러나 이것은 이러한 경우 중 하나가 아닙니다. 두 번째 예는 더 읽기 쉬운 IMHO이지만, 더 읽기 쉬운 것은 루프를 별도의 함수로 추출한 다음 일치하는 것을 찾으면 반환하는 것입니다. 의사 코드에서는 정확한 구문을 모릅니다.

if (!in_array($ip, $ips)) throw new Exception('Not allowed');

에 대해 무엇이 나쁜 GOTO가요? 구조화 된 프로그래밍은 함수와 제어 구조를 사용하여 코드를 구성하므로 구문 구조는 논리 구조를 반영합니다. 조건부로만 실행되는 경우 조건문 블록에 나타납니다. 루프에서 무언가가 실행되면 루프 블록에 나타납니다. GOTO임의로 건너 뛰어 구문 구조를 우회하여 코드를 따르기가 더 어려워집니다.

물론 다른 선택을하지 않아도 GOTO기능과 제어 구조로 동일한 효과를 얻을 수 있다면 바람직합니다.


5
@jameslarge 자세히 it's easier to write good optimizing compilers for "structured" languages.관리 하시겠습니까? 이에 반해 Rust folks는 확인 및 최적화가 더 간단하기 때문에 루프를 계속 대체하고, 계속하고, 중단하고,이를 gotos로 대체하는 컴파일러의 중간 표현 인 MIR을 도입 했습니다.
8bittree

6
"다른 선택이 없다면 GOTO를 사용하십시오"이것은 매우 드문 일입니다. 기존 코드 또는 이와 유사한 넌센스를 리팩토링하는 것을 막는 완전히 어리석은 제한 외에는 다른 선택이없는 경우를 솔직히 생각할 수 없습니다 .
jpmc26

8
또한 goto(OP의 두 번째 예에서와 같이) 플래그와 조건의 랫트 중첩으로 a 를 에뮬레이트하는 IMO 는을 사용하는 jut보다 읽기가 훨씬 어렵습니다 goto.

3
@ 8 비트 트리 : 구조화 된 프로그래밍은 컴파일러의 대상 언어가 아닌 소스 언어를위한 것입니다. 네이티브 컴파일러의 대상 언어는 CPU 명령어이며 , 프로그래밍 언어의 의미에서 "구조화 되지 않은 "결정입니다.
Robert Harvey

4
@ 8bittree MIR에 대한 귀하의 질문에 대한 답변은 귀하가 제공 한 링크에 있습니다. " 즉, Rust에서는 goto가 허용되지 않기 때문에 구조화되어 있고 gotos의 중간 버전도 알고 있습니다. 궁극적으로 코드는 기계 명령처럼 가야합니다. 내가 당신의 링크에서 얻는 것은 그들이 단순히 고급 언어에서 저급 언어로의 변환의 증분 단계를 추가한다는 것입니다.
JimmyJames

17

다른 사람들이 말했듯이 문제는 goto그 자체 가 아닙니다 . 문제는 사람들이 사용 goto하는 방식과 코드를 이해하고 유지하기가 더 어렵게 만드는 방법에 있습니다.

다음 코드 스 니펫을 가정하십시오.

       i = 4;
label: printf( "%d\n", i );

어떤 값이 인쇄 i됩니까? 언제 인쇄됩니까? 함수 의 모든 인스턴스 를 설명 할 때까지 goto label알 수 없습니다. 라벨의 단순한 존재는 파괴 간단한 검사하여 코드를 디버깅 할 수있는 능력을. 하나 또는 두 개의 분기가있는 작은 기능의 경우 큰 문제가되지 않습니다. 작은 기능이 아닌 경우

90 년대 초반에 우리는 3D 그래픽 디스플레이를 구동하고 더 빨리 실행하도록하는 C 코드 더미를 받았습니다. 그것은 약 5000 줄의 코드 였지만 모든 코드 는 안에 있었고 main저자 goto는 양방향으로 약 15 가지 정도 의 분기를 사용했습니다. 이것은 처음에는 잘못된 코드 였지만, 그 존재로 goto인해 훨씬 ​​더 나빠졌습니다. 제어 흐름을 해결하기 위해 동료가 약 2 주가 걸렸습니다. 더 좋은 점 goto은 코드가 자체와 밀접하게 결합되어 무언가를 깨지 않고는 변경할 수 없었 습니다.

우리는 레벨 1 최적화로 컴파일을 시도했으며 컴파일러는 사용 가능한 모든 RAM, 사용 가능한 모든 스왑을 먹은 다음 시스템을 당황 시켰습니다 (아마도 gotos 와는 관련이 없었지만 그 일화를 버리는 것을 좋아합니다).

결국 고객에게 두 가지 옵션을 제공했습니다. 모든 것을 처음부터 다시 작성하거나 더 빠른 하드웨어를 구입하도록하겠습니다.

그들은 더 빠른 하드웨어를 구입했습니다.

Bode의 사용 규칙 goto:

  1. 분기 앞으로 만;
  2. 제어 구조를 우회하지 마십시오 (즉, ifor for또는 while문의 본문으로 분기하지 마십시오 ).
  3. goto제어 구조 대신 사용하지 마십시오

a goto 정답 인 경우가 있지만 드문 경우입니다 (깊게 중첩 된 루프에서 벗어나는 것은 내가 사용하는 유일한 장소입니다).

편집하다

마지막 문장을 확장하여에 대한 몇 가지 유효한 사용 사례 중 하나입니다 goto. 다음과 같은 기능이 있다고 가정하십시오.

T ***myalloc( size_t N, size_t M, size_t P )
{
  size_t i, j, k;

  T ***arr = malloc( sizeof *arr * N );
  for ( i = 0; i < N; i ++ )
  {
    arr[i] = malloc( sizeof *arr[i] * M );
    for ( j = 0; j < M; j++ )
    {
      arr[i][j] = malloc( sizeof *arr[i][j] * P );
      for ( k = 0; k < P; k++ )
        arr[i][j][k] = initial_value();
    }
  }
  return arr;
}

이제 문제가 있습니다. malloc통화 중 하나 가 중간에 실패하면 어떻게됩니까? 아마도 이벤트 일 수도 있지만, 부분적으로 할당 된 배열을 반환하거나 함수에서 오류가 발생하는 것을 막고 싶지도 않습니다. 우리는 스스로 정리하고 부분적으로 할당 된 메모리를 할당 해제하려고합니다. 나쁜 할당 자에 예외를 던지는 언어에서는 매우 간단합니다. 이미 할당 된 것을 해제하기 위해 예외 처리기를 작성하기 만하면됩니다.

C에서는 구조화 된 예외 처리가 없습니다. 각 malloc호출 의 반환 값을 확인 하고 적절한 조치를 취해야합니다.

T ***myalloc( size_t N, size_t M, size_t P )
{
  size_t i, j, k;

  T ***arr = malloc( sizeof *arr * N );
  if ( arr )
  {
    for ( i = 0; i < N; i ++ )
    {
      if ( !(arr[i] = malloc( sizeof *arr[i] * M )) )
        goto cleanup_1;

      for ( j = 0; j < M; j++ )
      {
        if ( !(arr[i][j] = malloc( sizeof *arr[i][j] * P )) )
          goto cleanup_2;

        for ( k = 0; k < P; k++ )
          arr[i][j][k] = initial_value();
      }
    }
  }
  goto done;

  cleanup_2:
    // We failed while allocating arr[i][j]; clean up the previously allocated arr[i][j]
    while ( j-- )
      free( arr[i][j] );
    free( arr[i] );
    // fall through

  cleanup_1:
    // We failed while allocating arr[i]; free up all previously allocated arr[i][j]
    while ( i-- )
    {
      for ( j = 0; j < M; j++ )
        free( arr[i][j] );
      free( arr[i] );
    }

    free( arr );
    arr = NULL;

  done:
    return arr;
}

우리는 이것을 사용하지 않고 이것을 할 수 있습니까 goto? 물론 우리는 할 수 있습니다-약간의 추가 부기가 필요합니다 (실제로 그것이 내가 취할 경로입니다). 사용하는 곳은 장소를 찾는 경우에, goto아닌 바로 나쁜 관행 또는 디자인의 표시, 이것은 몇 가지 중 하나입니다.


나는이 규칙을 좋아한다. 난 아직 사용하지 것이다 goto-I 규칙에서 사용하지 않을 경우에도 이들에 따라 모두 가 사용할 수 분기의 유일한 형태 않는 한 언어하지만 난 그것을 디버깅 악몽을 너무 많이하지 않다고 볼 수있다 goto이 규칙에 따라 작성된 경우입니다.
와일드 카드

깊게 중첩 된 루프에서 벗어나려면 해당 루프를 다른 함수로 만들고 반환해야합니다.
bunyaCloven

6
누군가가 나를 위해 그것을 요약 한 것처럼 : "이것은가는 문제가 아니라, 온 문제입니다." 소프트웨어 최적화 전문가로서 나는 구조화되지 않은 제어 흐름이 루프를 위해 컴파일러 (및 인간!)를 던질 수 있다고 동의합니다. 한 번은 BLAS 함수에서 간단한 상태 머신 (5 개 상태 중 4 개 상태)을 해독하는 데 몇 시간을 보냈습니다 GOTO.
njuffa

@njuffa "소프트웨어 최적화 전문가로서 비정형 화 된 제어 흐름으로 인해 컴파일러 (및 인간!)가 루프를 발생시킬 수 있다고 동의했습니다." -더 자세한 내용은? 요즘에는 거의 모든 최적화 컴파일러가 SSA를 IR로 사용한다고 생각했습니다. 즉, 아래에 goto-like 코드를 사용하고 있음을 의미합니다.
Maciej Piechotka

@MaciejPiechotka 저는 컴파일러 엔지니어가 아닙니다. 예, 최신 컴파일러는 모두 중간 표현으로 SSA를 사용하는 것으로 보입니다. 컴파일러는 단일 엔트리 단일 종료 제어 구조를 선호하지만 SSA 사용이 어떻게 작동하는지 잘 모르겠습니까? 생성 된 기계 코드 및 컴파일러 리소스 사용량을 관찰하고 컴파일러 엔지니어와의 논의를 통해 비정형 제어 흐름은 아마도 "come-from"문제로 인한 코드 변환 최적화를 방해합니다. 컴파일러가 최적화를 너무 비싸게 건너 뛰기로 결정하면 리소스 사용 (시간, 메모리)이 코드 성능에 부정적인 영향을 줄 수 있습니다.
njuffa

12

return, break, continuethrow/ catch그들이 코드의 다른 부분에 대한 모든 전송 제어 및 모든 gotos로 구현 될 수있다 - - 모든 본질적으로 gotos 있습니다 내가 학교 프로젝트 때문에 한 번 한 사실, 파스칼 강사 파스칼은보다 얼마나 훨씬 더 말하고 있었다 구조 때문에 기본입니다 ... 그래서 나는 반대해야했습니다 ...

소프트웨어 공학에서 가장 중요한 것은 (이 용어를 코딩보다 지속적으로 개선 및 유지 보수가 필요한 다른 엔지니어와 함께 코드베이스를 생성하기 위해 누군가가 지불하는 상황을 언급하기 위해 사용합니다.) -무언가를하도록하는 것은 거의 이차적입니다. 코드는 한 번만 작성되지만 대부분의 경우 사람들은 며칠, 몇 주 동안 재 방문 / 방문, 개선 및 수정을 할 것입니다. 그리고 그들이 (또는 당신) 처음부터 시작하여 기억 / 그림을 그려야 할 때마다 귀하의 코드.

수년 동안 언어에 추가 된 대부분의 기능은 소프트웨어를 유지 관리하기 쉽고 작성하기 쉽지 않게 만드는 것입니다 (일부 언어는 그러한 방향으로 진행되지만 종종 장기적인 문제를 일으킬 수 있음).

유사한 흐름 제어문과 비교할 때 GOTO는 최대한 잘 따르기 쉽고 (당신이 제안한 경우에 사용되는 단일 goto) 악용 될 때의 악몽과 매우 쉽게 악용됩니다 ...

그래서 몇 년 동안 스파게티 악몽을 다룬 후에 우리는 방금 "아니오"라고 말했습니다. 커뮤니티로서 우리는 이것을 받아들이지 않을 것입니다. 당신은 그것들을 사용할 수는 있지만 ... 완벽한 경우라도 다음 사람은 당신이 공동체의 역사를 이해하지 못하기 때문에 당신이 끔찍한 프로그래머라고 가정 할 것입니다.

함수, 객체, 스코핑, 캡슐화, 주석 (!) 등의 코드를 이해하기 쉽게하기 위해 많은 다른 구조가 개발되었습니다. "DRY"(중복 방지) 및 "YAGNI"와 같은 더 중요한 패턴 / 프로세스 (코드의 과잉 생성 / 복잡함 감소)-실제로 NEXT 직원이 코드를 읽을 수 있도록 가져 오기만합니다 (아마도 당신이 될 것입니다)


3
나는 단지 문장이를 upvoting 해요 "... 가장 중요한 것은 코드를 읽을 수를하고있다, 그것은 뭔가가 거의 차있다 할지고." 나는 그것을 조금 다르게 말할 것이다. 그것은 너무 많은 코드를 만드는 아니에요 읽을 수를 같은 코드 만들기 간단 . 그러나 어느 쪽이든, 만드는 것이 오 - 그래서 - 사실 일하는 차입니다.
와일드 카드

" return, break, continuethrow/ catch, 전자 존중의 원칙에 동의 모두가 본질적으로 gotos있다" 구조화 프로그래밍 (당신이 예외에 대해 주장 할 수 있지만), 이동-에 확실히하지 않습니다. 이 질문에 비추어 볼 때,이 발언으로 많은 것을 얻지 못합니다.
Eric

@eric GOTO를 사용하여 모든 문장을 모델링 할 수 있습니다. GOTO는 모두 구조화 된 프로그래밍 원칙에 동의 할 수 있습니다. 이들은 단순히 다른 구문을 가지고 있으며 기능을 정확하게 복제하려면 "if"와 같은 다른 작업을 포함해야합니다. 구조화 된 버전의 장점은 특정 대상 만 지원하도록 제한되어 있다는 것입니다. 대략 대상이있는 위치에 계속 표시되는 경우 알 수 있습니다. 내가 언급 한 이유는 그것이 문제가되는 가연성이며 그것이 올바르게 사용될 수 없다는 것이 아니라고 지적하는 것이 었습니다.
Bill K

7

GOTO도구입니다. 그것은 선악에 사용될 수 있습니다.

예전에는 FORTRAN과 BASIC이 거의 유일한 도구였습니다.

당시의 코드를 볼 때, 코드를 볼 때 코드가 GOTO왜 있는지 알아 내야합니다. 그것은 당신이 빨리 이해할 수있는 표준 관용구의 일부일 수 있습니다. 당신이봤을 때까지 당신은 알지 못하고 착각하기 쉽습니다.

사람들은 더 나은 것을 원했고 더 진보 된 제어 구조가 발명되었습니다. 이것들은 대부분의 사용 사례를 다루었으며, 나쁜 사람에 의해 화상을 입은 사람들은 그 사용 GOTO을 완전히 금지하고 싶었습니다.

아이러니하게도 GOTO드물게 그렇게 나쁘지 않습니다. 당신이 그것을 볼 때, 당신 은 특별한 일이 있다는 것을 알고 있으며, 해당 라벨이 근처의 유일한 라벨이기 때문에 쉽게 찾을 수 있습니다.

오늘로 빨리 감기. 당신은 강사 교육 프로그래밍입니다. 당신은 수있다 "대부분의 경우는 새로운 고급 구조를 사용해야하지만, 어떤 경우에는 간단한 말을 GOTO더 읽을 수 있습니다." 학생들은 그것을 이해하지 못할 것입니다. GOTO읽을 수없는 코드를 만들기 위해 남용 할 것입니다.

대신 " GOTO나쁘고 GOTO악하다. GOTO시험에 실패한다 "고 말합니다. 학생들은 그것을 이해할 것 입니다 !


4
이것은 더 이상 사용되지 않는 모든 것에 적용됩니다. 글로벌 한글자 변수 이름 자체 수정 코드. 평가. 심지어 필터링되지 않은 사용자 입력이 의심됩니다. 일단 우리가 전염병과 같은 것들을 피하기 위해 스스로를 조정했다면, 우리는 그것들이 잘 사용되어 특정 문제에 대한 올바른 해결책이 될 수 있는지 평가할 적절한 위치에 있습니다. 그 전에는 단순히 금지 된 것으로 취급하는 것이 가장 좋습니다.
Dewi Morgan

4

를 제외한 PHP (및 대부분의 언어)의goto 모든 흐름 구성은 계층 적으로 범위가 지정됩니다.

눈을 가늘게 뜨고 검사 한 코드를 상상해보십시오.

a;
foo {
    b;
}
c;

에 관계없이 제어 구조는 무엇 foo이고 ( if, while, 등), 거기에 대한 특정 허용 주문에만있다 a, b그리고 c.

당신은 할 수 a- b- c또는 a- c, 또는 a- b- b- b- c. 하지만 당신은 할 수 결코 없다 b- c또는 a- b- a- c.

...하지 않는 한 goto.

$a = 1;
first:
echo 'a';
if ($a === 1) {
    echo 'b';
    $a = 2;
    goto first;
}
echo 'c'; 

goto(특히 거꾸로 goto) 그냥 방치하고 계층적이고 차단 된 흐름 구조를 사용하는 것이 가장 좋을 정도로 번거로울 수 있습니다.

goto장소가 있지만 주로 저수준 언어의 미세 최적화로 사용됩니다. IMO, PHP에는 좋은 곳이 없습니다.


참고로, 예제 코드는 귀하의 제안 중 하나보다 더 잘 작성 될 수 있습니다.

if(!in_array($ip, $ips, true)) {
    throw new Exception('Not allowed');
}

2

저급 언어에서는 GOTO가 불가피합니다. 그러나 높은 수준 에서는 프로그램을 읽기가 어렵 기 때문에 언어가 지원하는 경우 피해야합니다 .

모든 것이 코드를 읽기 어렵게 만듭니다. 고급 언어는 어셈블러 나 C와 같은 저급 언어보다 코드를 읽기 쉽게 만들어줍니다.

GOTO는 지구 온난화를 유발하지 않으며 제 3 세계의 빈곤을 초래합니다. 코드를 읽기가 더 어려워집니다.

대부분의 현대 언어에는 제어 구조가있어 GOTO가 불필요합니다. Java와 같은 일부는 심지어 그것을 가지고 있지 않습니다.

실제로, 스파게티 코드 라는 용어 는 구조화되지 않은 분기 구조에 의해 복잡하고 따르기 어려운 코드 원인에서 비롯됩니다.


6
goto코드를 읽기 쉽게 만들 수 있습니다. 단일 변수에 비해 추가 변수와 중첩 분기를 만들면 코드를 읽고 이해하기가 훨씬 어렵습니다.
Matthew Whited

@MatthewWhited 아마도 10 줄의 방법으로 단일 goto를 가지고있을 것입니다. 그러나 대부분의 방법은 길이가 10 줄이 아니며 사람들이 GOTO를 사용할 때는 대부분 "한 번만"사용하지 않습니다.
Tulains Córdova

2
@MatthewWhited 사실, 스파게티 코드 라는 용어 는 구조화되지 않은 분기 구조로 인한 코드를 따르기 어렵고 복잡하기 때문에 유래합니다. 아니면 스파게티 코드가 더 쉽게 빨간색입니까? 아마도. 비닐이 돌아오고 있는데 왜 GOTO가 안될까요?
Tulains Córdova

3
@Tulains 사람들이 계속 불평하고 있기 때문에 그러한 나쁜 것들이 존재한다고 생각해야하지만, 내가 등장하는 대부분의 시간 goto은 복잡한 스파게티 코드의 예가 아니라 상당히 간단한 것입니다. 't는 그것을 구문이 : 두 개의 가장 일반적인 예는 여러 루프와 영업의 예의 탈옥 있습니다 goto구현하는 데 사용됩니다 for- else.

1
구조화되지 않은 스파게티 코드는 함수 / 방법이 존재하지 않는 언어에서 제공됩니다. goto예외 재시도, 롤백, 상태 시스템과 같은 작업에도 적합합니다.
Matthew Whited

1

goto진술 자체 에는 아무런 문제가 없습니다 . 이 진술을 부적절하게 사용하는 일부 사람들에게는 문제가 있습니다.

JacquesB가 말한 것 외에도 (C에서 오류 처리), goto중첩되지 않은 루프를 종료하는 데 사용 하고 있습니다 break. 이 경우을 사용하는 것이 좋습니다 break.

그러나 중첩 루프 시나리오가 있다면 사용하는 goto것이 더 우아하고 간단합니다. 예를 들면 다음과 같습니다.

$allowed = false;

foreach ($ips as $i) {
    foreach ($ips2 as $i2) {
        if ($ip === $i && $ip === $i2) {
            $allowed = true;
            goto out;
        }
    }
}

out:

if (!$allowed) {
    throw new Exception('Not allowed');
}

중첩 루프가 필요하지 않기 때문에 위의 예는 특정 문제에 적합하지 않습니다. 그러나 중첩 루프 부분 만 보길 바랍니다.

좋은 점 : IP 목록이 작 으면 방법이 좋습니다. 그러나 목록이 커지면 접근 방식에 최악의 런타임 복잡성이 O (n) 이라는 점을 알고 있어야합니다 . 목록이 커지면 O (log n) (예 : 트리 구조) 또는 O (1) (충돌이없는 해시 테이블 ) 을 달성하는 다른 방법을 사용할 수 있습니다 .


6
나는 PHP에 대해 잘 모르겠지만, 많은 언어를 사용하여 지원 break하고 continue둘 중 하나 일반적이어야 번호와 (/ 휴식에 해당 라벨이있는 루프를 계속) 또는 라벨 (휴식 시간에 / 루프의 많은 레이어를 계속) goto중첩 루프 에 사용 하는 것이 좋습니다 .
8bittree

@ 8bittree 좋은 지적. PHP의 휴식 이 그렇게 멋진 지 몰랐습니다 . 나는 C의 휴식 이 그렇게 멋진 것이 아니라는 것을 알고 있습니다. Perl의 중단 ( 마지막 이라고도 함)은 C와 비슷했지만 (PHP와 같이 공평하지는 않지만) 어느 시점 이후에는 너무 화려했습니다. 더 많은 언어가 멋진 버전의 break를 도입함에 따라 내 대답이 점점 더 유용
caveman

3
깊이 값을 가진 중단은 추가 변수가 없으면 문제를 해결하지 못합니다. 더 복잡한 수준을 만드는 자체 변수.
Matthew Whited

물론 중첩 루프가 있다고해서 이동해야한다는 의미는 아닙니다. 그 상황을 우아하게 처리하는 다른 방법이 있습니다.
NPSF3000

@ NPSF3000 goto 문 을 사용하지 않고 종료 할 수있는 중첩 루프의 예를 제공하는 동시에 깊이를 지정 하는 멋진 중단 버전이없는 언어를 사용할 수 있습니까?
원시인

0

goto를 사용하면 더 빠른 코드를 작성할 수 있습니다!

참된. 상관 없어

어셈블리에 Goto가 존재합니다! 그들은 단지 그것을 jmp라고 부릅니다.

참된. 상관 없어

Goto는보다 간단하게 문제를 해결합니다.

참된. 상관 없어

goto를 사용하는 훈련 된 개발자 코드를 사용하면 쉽게 읽을 수 있습니다.

참된. 그러나 나는 그 훈련 된 코더였습니다. 나는 시간이 지남에 따라 코딩이 어떻게되는지 보았습니다. Goto잘 시작합니다. 그런 다음 코드 세트를 재사용하려는 충동이 생겨났습니다. 곧 프로그램 상태를 살펴본 후에도 무슨 일이 벌어지고 있는지 전혀 알 수없는 중단 점이 있습니다. Goto코드를 추론하기가 어렵습니다. 우리는 일을 정말 열심히 작성했습니다 while, do while, for, for each switch, subroutines, functions와이 물건을하고 있기 때문에 더 모든 것을하고, if그리고 것은 goto뇌에 어렵다.

그래서 안돼. 우리는보고 싶지 않습니다 goto. 물론 바이너리에서 잘 작동하지만 소스에서 볼 필요는 없습니다. 실제로 if약간 흔들리는 것처럼 보이기 시작합니다.


1
"Goto는 문제를보다 간단하게 해결합니다." / "참. 상관 없어." -가장 확장 가능한 것을 선호하는 간단한 솔루션을 의도적으로 피하는 코드를보고 싶지 않습니다. (YAGNI 들어?)
user253751

1
@Wildcard if와 goto는 다른 방법으로 가장 잘 해결 된 문제를 해결하는 매우 간단한 방법입니다. 그들은 매달린 과일입니다. 특정 언어에 관한 것이 아닙니다. Goto다른 코드 비트 문제를 만들어서 문제를 추상화 할 수 있습니다. If그 추상화를 선택할 수 있습니다. 추상화하는 더 좋은 방법과 추상화를 선택하는 더 좋은 방법이 있습니다. 하나의 다형성 .
candied_orange

2
나는 당신에게 동의하지만, 이것은 잘못된 말로 대답합니다. "진실 하지마"는 설득력있는 주장이 아닙니다. 나는 당신의 주요 메시지는 이것이라고 생각합니다. goto는 효율적이고 강력한 도구를 선호하는 사람들에게 호소력이 있지만 나중에 치료를 받더라도 놀랍게도 많은 시간을 낭비합니다.
Artelius

1
@artelius "진정한 상관 없음"테마는 설득력있는 것은 아닙니다. 그것은 내가 간직하고 여전히 그것에 대해 내려갈 많은 점들을 설명하기위한 것입니다. 따라서 저와 같은 주장을하는 것은 무의미합니다. 그게 내 요점이 아니니까 요점을 알아?
candied_orange 3

1
나는 단지 좋은 대답은 단지 당신의 의견을 진술 할뿐만 아니라 그것을 설명하고 독자가 자신의 판단을 할 수있게한다고 믿습니다. 고토의 좋은 점이 문제를 능가하기에 충분 하지 않은 이유 는 분명하지 않습니다. 우리 대부분 은 고토와 관련 이없는 벌레를 찾으려고 몇 시간 동안 머리를 깎아 보냈습니다 . 추론하기 어려운 유일한 구조는 아닙니다. 이 질문을하는 사람은 아마도 경험이 훨씬 적고 사물을 고려할 필요가 있습니다.
Artelius

-1

어셈블리 언어에는 일반적으로 조건부 / 무조건 부 점프 만 있습니다 (GOTO와 동일). FORTRAN 및 BASIC의 이전 구현에서는 카운트 된 반복 (DO 루프)을 넘어서는 제어 블록 명령문이 없었으므로 다른 모든 제어 흐름은 IF 및 GOTO로 남겨졌습니다. 이 언어들은 숫자로 표시된 문장으로 끝났으며, 결과적으로이 언어로 작성된 코드는 따르기가 어려웠고 실수를 저지르기 쉬웠습니다.

요점을 강조하기 위해 면밀하게 발명 된 " COME FROM "문이 있습니다.

실제로 C, C ++, C #, PASCAL, Java 등과 같은 언어에서는 GOTO를 사용할 필요가 없습니다. 거의 확실하게 효율적이고 훨씬 더 유지 보수가 가능한 대안적인 구성이 사용될 수있다. 소스 파일에서 하나의 GOTO는 문제가되지 않습니다. 문제는 코드 단위를 따르기가 어려워지고 오류가 발생하기 쉽다는 점이 많지 않다는 것입니다. 그것이 가능한 지혜가 GOTO를 피하는 이유입니다.

고토 문에 위키 피 디아 기사는 도움이 될 수 있습니다

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.