goto
ほとんどの場合、推奨されていません。このステートメントを使用する価値はありますか?
goto
必須ではありません。これは、状態遷移のセマンティクスに最も近いものなので、命令型言語でそれらを実装する最も合理的な方法です。そして、その宛先はソースからかなり離れている可能性があり、読みやすさを妨げることはありません。そのようなコードの私のお気に入りの例は、アドベンチャーゲームのDE Knuthの実装です。
goto
ほとんどの場合、推奨されていません。このステートメントを使用する価値はありますか?
goto
必須ではありません。これは、状態遷移のセマンティクスに最も近いものなので、命令型言語でそれらを実装する最も合理的な方法です。そして、その宛先はソースからかなり離れている可能性があり、読みやすさを妨げることはありません。そのようなコードの私のお気に入りの例は、アドベンチャーゲームのDE Knuthの実装です。
回答:
これはStack Overflowで何度か議論されてきましたが、Chris Gillumは次の可能な用途を要約しましたgoto
。
関数をきれいに終了する
多くの場合、関数内でリソースを割り当て、複数の場所で終了する必要があります。プログラマは、関数のすべての「終了ポイント」がすべてクリーンアップラベルに移動するように、関数の最後にリソースクリーンアップコードを配置することにより、コードを簡素化できます。このように、関数の「終了ポイント」ごとにクリーンアップコードを記述する必要はありません。
ネストされたループを終了する
ネストされたループ内にあり、すべてのループから抜け出す必要がある場合、gotoを使用すると、breakステートメントやif-checkよりもはるかにクリーンでシンプルになります。
低レベルのパフォーマンスの改善
これはパフォーマンスが重要なコードでのみ有効ですが、gotoステートメントは非常に高速に実行され、関数内を移動するときに後押しすることができます。ただし、コンパイラは通常、gotoを含むコードを最適化できないため、これは両刃の剣です。
私は、他の多くの人が主張するように、これらのすべてのケースで、使用はgoto
コード化されたコーナーから抜け出す手段として使用され、一般的にリファクタリング可能なコードの症状であると主張します。
finally
現代言語のブロックによって非常にきれいに解決され、2番目の問題はラベル付きbreak
のs によって解決されます。ただし、Cにこだわっている場合は、goto
これらの問題をエレガントに解決する唯一の方法です。
finally
はそれらの条件下でのみ有効です。gotoを使用することが非常にまれですが、有効な状況があります。
break 3
かbreak myLabel
とgoto myLabel
。ああ、まさにキーワードです。を使用している場合break
、continue
または類似のキーワードを使用しているgoto
場合(使用しfor, while, foreach, do/loop
ている場合は条件付きgotoを使用している場合)
上位レベルの制御フロー構造は、問題領域の概念に対応する傾向があります。if / elseは、何らかの条件に基づいた決定です。ループは、何らかのアクションを繰り返し実行することを意味します。breakステートメントでも「これを繰り返し行っていましたが、今は停止する必要があります」と書かれています。
一方、gotoステートメントは、問題の領域ではなく、実行中のプログラムの概念に対応する傾向があります。それはプログラムの指定されたポイントで実行を続けると言います。コードを読んでいる人は、問題のドメインに関してそれが何を意味するかを推測する必要があります。
もちろん、すべての高レベルの構造は、gotoおよび単純な条件分岐の観点から定義できます。だからといって、彼らが単に変装したゴトだというわけではありません。それらを制限されたゴトと考えてください-そしてそれはそれらを有用にする制限です。breakステートメントは、ループを囲むループの最後へのジャンプとして実装されますが、ループ全体を操作していると考える方が適切です。
他のすべてが等しい場合、問題のドメインの構造を反映した構造のコードは、読みやすく保守しやすい傾向があります。
gotoステートメントが絶対に必要な場合はありません(その効果の定理があります)が、それが最も悪い解決策になる場合があります。これらのケースは、言語がサポートする上位レベルの構成に応じて、言語ごとに異なります。
たとえば、Cでは、gotoが適切な3つの基本的なシナリオがあると思います。
一方、明示的な有限状態マシンは、ループ内でswitchステートメントを使用して実装することもできます。これには、すべての状態がコード内の同じ場所から開始されるという利点があります。これは、デバッグなどに役立ちます。
かなり現代的な言語(if / elseおよびループをサポートする言語)でgotoを使用する主な目的は、言語にない制御フロー構成をシミュレートすることです。
goto
です。SSSMは、実行状態からSM状態を分離するので、使用するのに適した構造であることがよくありますが、実際には "gotos"を排除しません。
確かにプログラミング言語に依存します。主な理由goto
は議論の余地がありますが、それはコンパイラがそれをあまりにも自由に使用できるようにするときに生じる悪影響のためです。たとえば、goto
初期化されていない変数にアクセスしたり、さらに悪いことに別のメソッドにジャンプして呼び出しスタックを台無しにできるような方法で使用できる場合、問題が発生する可能性があります。無意味な制御フローを許可しないのは、コンパイラの責任です。
Javaはgoto
完全に拒否することでこの問題を「解決」しようとしました。ただし、Javaではブロックreturn
内で使用finally
できるため、例外が誤って飲み込まれます。同じ問題がまだあります:コンパイラは仕事をしていません。goto
言語から削除しても、修正されていません。
C#では、goto
同様に安全ようでbreak
、continue
、try/catch/finally
とreturn
。初期化されていない変数を使用したり、finallyブロックなどから飛び出させたりすることはできません。コンパイラは文句を言います。これは、私が無意味な制御フローを言ったように、実際の問題を解決するからです。goto
明確な割り当ての分析やその他の妥当なコンパイラチェックを魔法のようにキャンセルしません。
goto
は悪ではないということですか?もしそうなら、それはgoto
C#だけでなく、コンストラクトで日常的に使用されるすべての現代言語の場合です
はい。あなたのループが深い複数のレベルにネストされているときに、goto
あるだけエレガントに内部ループを抜け出しの方法。もう1つのオプションは、フラグを設定し、そのフラグが条件を満たす場合に各ループから抜け出すことです。これは本当に見苦しく、かなりエラーが発生しやすいです。これらの場合、goto
単に優れています。
もちろん、Javaのラベル付きbreak
ステートメントは同じことをしますが、コード内の任意のポイントにジャンプすることを許可せずに、goto
悪をもたらすものを許可することなく問題をきれいに解決します。
Do
ループ。どうして?Do
ループとタイプへの深いブレークが必要な1つのループを変更できるためExit Do
、ありませんGoTo
。ネストされたループは常に発生します。スタックの破壊は、いくつかの時間に発生します。
落胆の大部分は、1960年代前半に無差別の力について説得力を持っていたジクストラ神の周りに作成された一種の「宗教」から生じます。
これはgoto
現代言語の声明とは何の関係もありません。現代言語の存在は、言語が提供するもの以外のコード構造の作成をサポートしているためです。
特に、上記の最初の主要なポイントは許可され、2番目のポイントgoto
は削除されます(ブロックから出た場合、スタックは適切に巻き戻され、すべての適切なデストラクタが呼び出されます)
この回答を参照して、gotoを使用していないコードでも読み込めない可能性があることを理解してください。問題はgoto自体ではなく、不適切な使用です。
私は使用せずに、プログラム全体を書くことができるif
だけで、for
。もちろん、読みにくく、不器用で不必要に複雑に見えます。
しかし、問題はそうではありませんfor
。それは私です。
以下のようなものbreak
、continue
、throw
、bool needed=true; while(needed) {...}
、などは、以上に注目されている仮面舞踏会 goto
、現代laguages-の発明後-50年はまだ彼らの囚人を望んでいることを、Djikstrarian狂信者のシミターから離れて脱出します。彼らは、ジクストラが話していたことを忘れ、彼のメモのタイトルのみを覚えています(GOTOは有害であると考えられ、彼のタイトルでもありません:編集者によって変更されました)。順番に配置された文字。
2011年です。ジクストラが説得力のgoto
あるGOTO
声明に対処することに注目していることを理解する時が来ました。
break n
はC ++では使用できないため、n-pleループから抜け出す必要がないgoto escape
場合でもですescape
。
あちこちの奇妙なgotoは、それが関数に対してローカルである限り、読みやすさを大きく損なうことはめったにありません。多くの場合、このコードでは、通常とは異なる制御構造の使用を必要とする異常な処理が行われているという事実に注意を向けることで、メリットがあります。
(ローカル)gotoが読みやすさを著しく損なっている場合、通常はgotoを含む関数が複雑になりすぎていることを示しています。
最後にCコードに入れたのは、インターロックループのペアを作成することでした。「許容できる」goto使用の通常の定義には適合しませんが、結果として、関数は大幅に小さくなり、明確になりました。gotoを回避するには、特にDRYの乱雑な違反が必要でした。
私はこの問題全体が間違ったツリーをほおばっているケースだと思う。
GOTO自体は問題に思えませんが、むしろ実際の罪の症状であるスパゲッティコードです。
GOTOがフロー制御ラインの大きな交差を引き起こす場合、それは悪い期間です。フロー制御ラインを通過しない場合、無害です。中間の灰色のゾーンにはループの救済などがありますが、すべての正当な灰色のケースをカバーする構造を追加していない言語がまだあります。
私が長年実際に使用しているのは、決定点がループの中間にあるループの場合だけです。重複したコード、フラグ、またはGOTOが残っています。GOTOソリューションは3つの中で最高だと思います。ここにはフロー制御線が交差することはなく、無害です。
goto
れ、ループにジャンプするsの有名なユースケースです(言語がこれを許可している場合;他のケースでは、ジャンプする中央のループから出て、通常はgoto
)なしで簡単です。
goto
を叫ぶことは、通常の構造化プログラミングパターンに適合しないと考えています。構造化されたプログラミングパターンに適合する制御フローは、適合しないものよりも推論が容易であるため、可能であればそのようなパターンの使用を試みる必要があります。コードがそのようなパターンに適合している場合、適合しないことを叫ぶべきではありません。一方、コードが実際にそのようなパターンに適合しない場合は、コードが実際に適合しないふりをするよりも、それについて叫ぶほうが良いかもしれません。
はい、gotoを使用して開発者のエクスペリエンスを向上させることができます。http: //adamjonrichardson.com/2012/02/06/long-live-the-goto-statement/
ただし、強力なツール(ポインター、多重継承など)と同様に、それを使用して訓練する必要があります。リンクで提供される例では、goto構造の使用を同じ関数/メソッドに制限し、新しい制御ブロック(ループ、switchステートメントなど)にジャンプする機能を無効にするPHPを使用しています。
私はノーと言うでしょう。GOTOを使用する必要がある場合は、コードを再設計する必要があると思います。
goto
従来のアセンブラコードをCに移植する場合に役立ちます。最初の例ではgoto
、アセンブラのbranch
命令の代わりとしてCに命令ごとに変換すると、非常に高速な移植が可能になります。
私は主張しません。gotoが解決に使用している問題に固有のツールに常に置き換える必要があります(言語で使用できない場合を除く)。たとえば、breakステートメントと例外は、ループエスケープとエラー処理の以前に解決された問題を解決します。
goto
がある場合、それらの言語には通常存在しないと私は主張します。
goto
非常に問題のあるドメインセマンティクスに最も近いのは、多くの場合です。それ以外のものはダーティハックになります。