これらの明白で関連性のあるケースに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、それがこのような明白でイモ関連のケースに使用されるとき、何がそんなに悪いのですか?


コメントは詳細なディスカッション用ではありません。この会話はチャットに移動さました
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構文には宣言されていない状態変数があります。それ自体は問題ではありませんが、これらの状態変数は小石のようなものです。1つを運ぶのは難しくありません。コードは変更されません。来月、プライベートアドレスとパブリックアドレスを区別するように求められます。その翌月、コードは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.

そして、そのコードをデバッグする必要がある人は、あなたとあなたの子供を呪います。

ダイクストラは次のように記述しています。

go toステートメントを自由に使用すると、プロセスの進行状況を説明する意味のある座標セットを見つけることが非常に難しくなります。

そして、それがGOTOが有害であると考えられる理由です。


22
その$list_contains_ip = false;声明は見当違いのようです
-Bergi

1
小石でいっぱいのバッグは簡単です。小石を入れるのに便利なバッグがあります。:p
whatsisname

13
@Bergi:そのとおりです。それは、これらのことを台無しにすることがいかに簡単かを示しています。
ウォレンボーン

6
@whatsisnameそのバッグは、それらを保持するために関数/クラス/パッケージと呼ばれます。gotoを使用することは、それらをジャグリングしてバッグを捨てるようなものです。
ファルコ

5
ダイクストラからの引用が大好きです。そのように言われたことは聞いていませんでしたが、それは本当に良い点です。最上部から最下部までのフローを使用する代わりに、突然、ページ全体をランダムにジャンプできるものがあります。簡潔に言えば、かなり印象的です。
ビルK

41

の正当な使用例がいくつかありますGOTO。たとえば、Cでのエラー処理とクリーンアップ、またはいくつかの形式のステートマシンの実装。しかし、これはこれらのケースの1つではありません。2番目の例はより読みやすい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の人々はMIRを導入しました。これは、コンパイラーの中間表現であり、ループ、継続、ブレークなどをgotoで具体的に置き換えます。
8bittree

6
「他に選択肢がない場合はGOTOを使用します」これは非常にまれです。正直に言って、既存のコードや同様のナンセンスのリファクタリングを妨げる完全にばかげた制限を除いて、他に選択肢がないケースは考えられません。
jpmc26

8
また、IMで、gotoフラグと条件のネズミのネストでエミュレートする(OPの2番目の例のように)は、を使用するjutよりもはるかに読みにくくなりますgoto

3
@ 8bittree:構造化プログラミングは、コンパイラのターゲット言語ではなく、ソース言語を対象としています。ネイティブコンパイラのターゲット言語はCPU命令であり、プログラミング言語の意味で「構造化」されていないことは明らかです。
ロバートハーベイ

4
@ 8bittree MIRに関する質問への答えは、あなたが提供したリンクにあります。 」言い換えると、Rustではgotoが許可されていないため、gotoが構造化され、gotoを使用した中間バージョンも同様であることがわかります。最終的に、コードは機械コマンドのようなgotoに移行する必要があります。私があなたのリンクから得たものは、彼らが単に高レベル言語から低レベル言語への変換に段階的なステップを追加しているということです。
ジミージェームズ

17

他の人が言ったように、問題はgotoそれ自体ではありません。問題は、人々がどのように使用するかgoto、そしてそれがどのようにコードを理解し維持するのを難しくするかということです。

次のコードスニペットを想定します。

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

どのような値が印刷されiますか? いつ印刷されますか?関数内のすべてのインスタンスを説明するまでgoto label、あなたは知ることができません。そのラベルの単純な存在は、単純な検査によってコードをデバッグする能力を破壊します。1つまたは2つのブランチを持つ小さな関数の場合、それほど問題はありません。小さくない関数の場合...

90年代初期の頃、3Dグラフィック表示を駆動し、より高速に実行するように指示されたCコードの山が与えられました。コードは約5000行だけでしたが、すべてはにmainあり、著者gotoは両方向に約15程度の分岐を使用しました。そもそもこれは悪いコードでしたが、それらgotoの存在はそれをさらに悪化させました。同僚が制御の流れを解明するのに約2週間かかりました。さらに良いことに、これらgotoはコードをそれ自体と密接に結び付けているため、何かを壊さずに変更を加えることはできません

レベル1の最適化でコンパイルしてみました。コンパイラーは使用可能なすべてのRAM、次に使用可能なすべてのスワップを使い果たし、システムをパニック状態にしました(おそらくgotos自体とは何の関係もありませんでしたが、その逸話を捨てるのが好きです)。

最後に、顧客に2つのオプションを与えました-ゼロからすべてを書き換えるか、より高速なハードウェアを購入しましょう。

彼らはより速いハードウェアを買いました。

使用するためのボードのルールgoto

  1. 前方分岐のみ。
  2. 制御構造をバイパスしないでください(つまり、ifor forまたはwhileステートメントの本体に分岐しないでください)。
  3. goto制御構造の代わりに使用しないでください

a goto 正しい答えである場合もあります、まれです(深く入れ子になったループから抜け出すことは、私がそれを使用する唯一の場所です)。

編集

その最後のステートメントを拡張して、の数少ない有効なユースケースの1つを以下に示します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呼び出しの1つが途中で失敗した場合はどうなりますか?イベントとは異なり、部分的に割り当てられた配列を返したくはありません。また、エラーを出して関数から脱出したいだけでもありません。自分の後にクリーンアップし、部分的に割り当てられたメモリの割り当てを解除する必要があります。悪いallocで例外をスローする言語では、それはかなり簡単です-既に割り当てられているものを解放するために例外ハンドラを書くだけです。

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か?もちろんできます-少し余分な簿記が必要です(そして、実際には、それが私がとる道です)。しかし、aの使用gotoすぐに悪い習慣やデザインの兆候ではない場所を探している場合、これは数少ないものの1つです。


私はこれらのルールが好きです。私はまだgotoこれらの規則に従ってさえも使用しません—言語で利用可能な唯一の分岐形式でない限り、まったく使用しません。gotoそれらがこれらの規則に従って書かれていれば。
ワイルドカード

深く入れ子になったループから抜け出す必要がある場合は、そのループを別の関数にして戻ります
bunyaCloven

6
誰かがかつて私にそれを要約したように:「それは行き詰まった問題ではなく、それは帰ってきた問題です」。ソフトウェア最適化のスペシャリストとして、非構造化制御フローがコンパイラー(および人間!)をループに投げ込む可能性があることに同意します。一度GOTO思い出すと、BLAS関数で単純なステートマシン(5つの状態のうち4つ)を解読するのに何時間も費やしました。
-njuffa

@njuffa「ソフトウェア最適化のスペシャリストとして、非構造化制御フローがループ(および人間!)にコンパイラーをスローする可能性があることに同意します。」-その他の詳細 ほぼすべての最適化コンパイラが、最近ではIRとしてSSAを使用していると思います。つまり、下にあるgotoのようなコードを使用しているということです。
マチェイピエチョトカ

@MaciejPiechotka私はコンパイラエンジニアではありません。はい、最新のコンパイラはすべて、中間表現でSSAを使用しているようです。コンパイラは、単一エントリ単一出口制御構造を好みますが、SSAの使用がそれにどのように影響するかわかりませんか?生成されたマシンコードとコンパイラリソースの使用状況を観察し、コンパイラエンジニアとの議論により、非構造化制御フローがコード変換の最適化に干渉します。これはおそらく「come-from」の問題によるものです。コンパイラーが高すぎると最適化をスキップすることを決定した場合、リソースの使用(時間、メモリー)はコードのパフォーマンスに悪影響を及ぼす可能性があります。
-njuffa

12

returnbreakcontinueおよびthrow/ catchすべての本質的GOTOSある-彼らのコードの別の部分へのすべての転送制御と、すべてのgotoで実装することができ-学校のプロジェクトでは、PASCALインストラクターがPascalはよりあったかずっと良いと言った後、実際に私はそのようにしました構造のために基本的な...だから私は反対しなければならなかった...

ソフトウェアエンジニアリングに関する最も重要なこと(コーディングでこの用語を使用して、継続的な改善と保守を必要とする他のエンジニアと一緒にコードベースを作成するために誰かから支払われている状況を指します)は、コードを読みやすくすることです- -何かをするためにそれを取得することはほとんど二次的です。あなたのコードは一度だけ書かれますが、ほとんどの場合、人々はそれを再検討/再学習、改善、修正するために何日も何週間も費やします-そして彼ら(またはあなた)はゼロから始めて覚え/数字を書き出そうとするたびにあなたのコード。

長年にわたって言語に追加された機能のほとんどは、ソフトウェアをより保守しやすくすることであり、書くのは簡単ではありません(ただし、一部の言語はその方向に向かっていますが、多くの場合、長期的な問題を引き起こします...)。

同様のフロー制御ステートメントと比較して、GOTOは最善の方法(お勧めのようなケースで使用される1つのgoto)でほぼ簡単に追跡でき、悪用されると悪夢になります...

数年間スパゲッティの悪夢を扱った後、私たちは「いいえ」と言ったばかりです。コミュニティとしてこれを受け入れるつもりはありません。あなたはそれらを使用することができます...しかし、それが完璧な場合であっても、次の男はあなたがコミュニティの歴史を理解していないのであなたがひどいプログラマーであると仮定します。

コードをよりわかりやすくするために、他の多くの構造が開発されています:関数、オブジェクト、スコープ、カプセル化、コメント(!)...、および「DRY」(複製を防止する)や「YAGNI」などのより重要なパターン/プロセス(コードの過剰な一般化/複雑さの削減)-すべては、実際に次の人があなたのコードを読むためだけにインポートします(最初に行ったことのほとんどを忘れた後は、おそらくあなたは誰でしょう?)


3
「最も重要なことは...コードを読みやすくすることです。何かをさせるにはほとんど二次的です」という文のためだけにこれを支持しています。 私はそれをほんの少し違うと言うでしょう。それはそんなに作るコードではありません読めるようにコード作るシンプルに。しかし、どちらの方法は、作ることをOH-SO-trueで行う何かが二次的です。
ワイルドカード

「、および/ 本質的GOTOS全て」の教義、かつて敬意を同意しない構造化プログラミング(あなたが例外について議論ができるが)、行く-に間違いありません。この質問に照らして、この発言ではあまり得られません。returnbreakcontinuethrowcatch
エリック

@eric GOTOを使用して、任意のステートメントをモデル化できます。GOTOがすべて構造化プログラミングの教義に一致することを確認できます。単に構文が異なるだけで、機能を正確に複製するには、「if」などの他の操作を含める必要があります。構造化されたバージョンの利点は、特定のターゲットのみをサポートするように制限されていることです。ターゲットが配置されるおおよその場所に継続して表示される場合はわかります。私がそれを言った理由は、それが正しく使用できないということではなく、それが問題である虐待であることを指摘することでした。
ビルK

7

GOTOツールです。善にも悪にも使用できます。

FORTRANとBASICを使用した悪い昔は、ほとんど唯一のツールでした。

当時のコードを見るとき、GOTOあなたがそれを見たとき、それがなぜそこにあるのかを理解しなければなりません。これは、すぐに理解できる標準的なイディオムの一部である可能性があります...または、あるべきではない悪夢のような制御構造の一部である可能性があります。見るまでわかりませんし、間違えやすいです。

人々はもっと良いものを望み、より高度な制御構造が発明されました。これらはほとんどのユースケースをカバーしており、悪者に火傷された人々はGOTOそれらを完全に禁止したかった。

皮肉なことに、GOTOまれなことでもそれほど悪くはありません。あなたが1を参照すると、あなたが知っている何か特別が起こっているがあり、それが唯一のラベルが近くにあるので、対応するラベルを見つけるのは簡単です。

今日に早送りします。あなたはプログラミングを教える講師です。あなたは可能性があり、「ほとんどの場合、あなたは、高度な新しい構文を使用する必要がありますが、いくつかのケースでは、単純なと言うGOTOより読みやすくすることができます。」学生はそれを理解するつもりはありません。彼らはGOTO判読不能なコードを作るために悪用しようとしています。

代わりに、「言うGOTO悪い。GOTO悪。 GOTO受験に失敗します。」学生はそれを理解ます!


4
これは実際、すべての非推奨のものに当てはまります。グローバル。1文字の変数名。自己修正コード。評価 さらに、フィルタリングされていないユーザー入力も疑っています。疫病のようなものを避けるように条件付ければ、適切な道標のある特定の使用が特定の問題の正しい解決策であるかどうかを評価するのに適した立場になります。それ以前は、それらを単に禁止されているものとして扱うのが最善です。
デウィモーガン

4

を除き、PHP(およびほとんどの言語)のgotoすべてのフロー構造は階層的にスコープされます。

目を細めた目で調べたコードを想像してください。

a;
foo {
    b;
}
c;

かかわらず、対照構築物は何のfooである(ifwhileなど)、そこのための特定の許可注文のみであるabc

あなたは持っている可能性がa- - bcまたはa- c、あるいはa- - b- b- 。b cしかし、あなたは可能性が決して持っていませんb- cまたはa- - b- 。ac

...あなたが持っていない限りgoto

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

goto(特に逆方向goto)面倒なことがあるため、そのままにして、階層化されたブロックされたフロー構造を使用するのが最善です。

gotosには場所がありますが、ほとんどが低レベル言語のマイクロ最適化としてです。IMO、PHPには良い場所はありません。


参考までに、サンプルコードはどちらの提案よりも優れた記述が可能です。

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

2

低レベルの言語では、GOTOは避けられません。しかし、高レベルでは、プログラムが読みにくくなるので(言語がサポートしている場合)避けるべきです。

結局、コードを読みにくくすることになります。高レベル言語は、たとえばアセンブラーやCなどの低レベル言語よりもコードを読みやすくするためにサポートされています。

GOTOは地球温暖化を引き起こさず、第三世界の貧困を引き起こしません。コードが読みにくくなるだけです。

最新の言語のほとんどには、GOTOを不要にする制御構造があります。Javaのようなものには、それさえもありません。

実際、スパゲッティコードという用語は、構造化されていない分岐構造による、複雑で追跡が困難なコードに由来しています。


6
gotoコードを読みやすくすることができます。単一のジャンプに対して追加の変数とネストされたブランチを作成した場合、コードの読み取りと理解がはるかに難しくなります。
マシューホワイトニング

@MatthewWhitedおそらく、10行のメソッドに1つのgotoがある場合。しかし、ほとんどのメソッドは10行の長さではなく、ほとんどの場合、人々はGOTOを「一度だけ」使用しません。
Tulainsコルドバ

2
@MatthewWhited実際、スパゲッティコードという用語は、構造化されていない分岐構造に起因する複雑で追跡が難しいコードに由来しています。それとも、スパゲッティコードは今や赤くなりやすいのでしょうか?多分。Vinylが戻ってきたのに、なぜGOTOしないのか。
Tulainsコルドバ

3
@Tulains人々はそれについて文句を言うので、そのような悪いことが存在すると信じなければなりませんが、私がgoto出てくるのはほとんどの場合、複雑なスパゲッティコードの例ではなく、かなり単純なもので、しばしばそうでない言語の制御フローのパターンをエミュレートします構文はありません。2つの最も一般的な例は、複数のループから抜け出すことと、goto実装に使用されるOPの例ですfor- else

1
非構造化スパゲッティコードは、関数/メソッドが存在しない言語に由来します。 goto例外の再試行、ロールバック、ステートマシンなどにも最適です。
マシューホワイトニング

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良い点。私は、PHPの破綻がそんな空想であることを知りませんでした。私は、Cの休憩はそれほど空想ではないことを知っています。Perlのブレーク(これを最後と呼びます)もCに似ていました(つまり、PHPのように派手ではありませんでした)が、ある時点で-あまりにも-派手になりました。私の答えは、より多くの言語が派手なバージョンのbreakを導入しているため、ますます役に立たなくなってきていると思います:)
caveman

3
深さの値を持つブレークは、追加の変数なしでは問題を解決しません。複雑さをさらに高める、自己の変数。
マシューホワイトニング

もちろん、ネストされたループがあるからといってgotoが必要というわけではありませんが、その状況をエレガントに処理する方法は他にもあります。
NPSF3000

@ NPSF3000 gotoステートメントを使用せずに終了できるネストされたループの例を提供してください。また、深さを指定する派手なバージョンのbreakを持たない言語も使用できますか?
穴居人

0

gotoを使用すると、より高速なコードを作成できます。

本当です。気にしないで。

後藤はアセンブリに存在します!彼らはそれを単にjmpと呼びます。

本当です。気にしないで。

後藤は、問題をより簡単に解決します。

本当です。気にしないで。

gotoを使用する統制のとれた開発者コードのほうが読みやすくなります。

本当です。しかし、私はその規律あるコーダーでした。私は時間の経過とともにコードに何が起こるかを見てきました。 Gotoうまく始めます。それからコードを再利用したいという衝動に駆られます。まもなく、ブレークポイントにいることに気づき、プログラムの状態を見ても何が起こっているのかまったくわかりません。 Gotoコードについて推論するのが難しくなります。私たちは本当に難しい作成を働いてきたwhiledo whileforfor each switchsubroutinesfunctions、そしてより多くのすべてでこのようなものをやっているためifgoto脳に難しいです。

だから 見たくないgoto。確かにそれは生きており、バイナリでもうまくいきますが、ソースで見る必要はありません。実際、if少し不安定に見え始めています。


1
「Gotoは問題をより簡単に解決します。」/「本当。気にしない。」-最も拡張性の高いものを支持して、単純な解決策を意図的に回避するコードを見るのは嫌です。(YAGNIを聞いた?)
user253751

1
@Wildcard ifとgotoは、他の方法で最もよく解決できる問題を解決する非常に簡単な方法です。それらは、ぶら下がっている果物です。特定の言語に関するものではありません。Gotoコードの問題を他のビットにすることで、問題を抽象化できます。 Ifその抽象化を選択できます。抽象化するより良い方法と、抽象化を選択するより良い方法があります。 ポリモーフィズム
candied_orange

2
私はあなたに同意しますが、これは不十分な言葉遣いの答えです。「本当、気にしない」は、何も説得力のある議論ではありません。あなたの主なメッセージはこれだと思います:gotoは効率的で強力なツールの使用を好む人には魅力的ですが、注意を払っても、驚くほど膨大な時間の無駄につながります。
アルテリウス

1
@artelius「true、do n't care」テーマは説得力のあるものではありません。これは、私がgotoに譲歩し、それでもなお反対する多くのポイントを説明するためのものです。したがって、これらの点について私と議論するのは無意味です。それは私のポイントではないので。ポイントを得る?
candied_orange

1
良い答えはあなたの意見を述べるだけでなく、それを説明し、読者が彼自身の判断を下すことができると信じています。現状では、なぜ gotoの良い点だけでは問題を上回るには不十分なのかは不明です。私たちのほとんどは、gotoを含まないバグを見つけるために何時間も髪を引っ張ってきました。推論するのが難しいのは、それだけではありません。この質問をする人は、おそらくあまり経験がなく、物事を視野に入れる必要があります。
アルテリウス

-1

アセンブリ言語には通常、条件付き/無条件ジャンプのみがあります(GOTOに相当します。FORTRANおよびBASICの古い実装では、カウントされた反復(DOループ)を超える制御ブロックステートメントはありません。結果として、これらの言語用に記述されたコードは、追跡するのが困難であり、間違いが発生しやすい場合がありました。

この点を強調するために、面倒に発明された「COME FROM」ステートメントがあります。

C、C ++、C#、PASCAL、Javaなどの言語でGOTOを使用する必要はほとんどありません。ほぼ確実に効率的で、はるかに保守性の高い代替構造を使用できます。ソースファイル内の1つのGOTOが問題にならないのは事実です。問題は、コードの単位を追跡するのが難しく、保守しやすいエラーが発生するのに多くの人を必要としないことです。だからこそ、可能な限りGOTOを避けることが一般に知られています。

gotoステートメントに関するこのウィキペディアの記事は役に立つかもしれません

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.