Goに「goto」という文があることに驚きました。「goto」ステートメントは過去のものであり、それがプログラムの実際のフローをふさいでしまうために邪悪であり、関数またはメソッドは常にフローを制御するより良い方法であると私は常に教えられてきました。
私は何かを逃しているに違いない。なぜGoogleはそれを含めたのですか?
Goに「goto」という文があることに驚きました。「goto」ステートメントは過去のものであり、それがプログラムの実際のフローをふさいでしまうために邪悪であり、関数またはメソッドは常にフローを制御するより良い方法であると私は常に教えられてきました。
私は何かを逃しているに違いない。なぜGoogleはそれを含めたのですか?
回答:
Go標準ライブラリのソースコードを実際にチェックすると、goto
sが実際に適切に適用されている場所を確認できます。
たとえば、math/gamma.go
ファイルでは次のgoto
ステートメントが使用されます。
for x < 0 {
if x > -1e-09 {
goto small
}
z = z / x
x = x + 1
}
for x < 2 {
if x < 1e-09 {
goto small
}
z = z / x
x = x + 1
}
if x == 2 {
return z
}
x = x - 2
p = (((((x*_gamP[0]+_gamP[1])*x+_gamP[2])*x+_gamP[3])*x+_gamP[4])*x+_gamP[5])*x + _gamP[6]
q = ((((((x*_gamQ[0]+_gamQ[1])*x+_gamQ[2])*x+_gamQ[3])*x+_gamQ[4])*x+_gamQ[5])*x+_gamQ[6])*x + _gamQ[7]
return z * p / q
small:
if x == 0 {
return Inf(1)
}
return z / ((1 + Euler*x) * x)
}
goto
この場合、単に制御フローのために使用される別の(ブール)変数を導入するから私たちを保存し、最後にをチェック。この場合、goto
ステートメントにより、コードが実際に読みやすくなり、追跡が容易になります(goto
あなたが述べた反対の意見に反して)。
また、goto
ステートメントには非常に具体的なユースケースがあることに注意してください。gotoの言語仕様では、スコープに入ってくる(宣言されている)変数を飛び越えたり、他の(コード)ブロックに飛び込んだりすることはできません。
small(x,z)
代わりに呼び出す関数を導入しないのですか?そうすれば、small:
ラベルでアクセス可能な変数について考える必要がなくなります。goには、コンパイラーでの特定のタイプのインライン化サポートがまだ欠けているためだと思います。
goto
、新しい変数が導入された後はラベルを指すことができません。「goto」ステートメントを実行しても、gotoの時点ではまだスコープ内になかった変数がスコープに入ってはなりません。
Gotoは、組み込みの制御機能のいずれもが望みどおりの動作を行わない場合、およびGotoを使用して必要な内容を表現できる場合に適しています。(gotoがない場合、一部の言語ではこれらのケースでは残念です。最終的に、ブールフラグを使用したり、gotoよりも悪い他のソリューションを使用したりして、制御機能を悪用することになります。)
他の制御機能(かなり明白な方法で使用される)が希望どおりの動作を実行できる場合は、gotoよりも優先して使用する必要があります。そうでない場合は、太字にしてgotoを使用してください。
最後に、Goのgotoには、いくつかのあいまいなバグを回避するために設計されたいくつかの制限があることに注意してください。仕様のこれらの制限を参照してください。
Gotoステートメントは、60年代と70年代のスパゲッティコードの時代以来、多くの信用を失っています。当時、ソフトウェア開発の方法論は非常に貧弱でした。しかし、Gotoは本来悪意はありませんが、もちろん、怠惰なプログラマーや熟練していないプログラマーによって悪用されたり悪用されたりする可能性があります。乱用されたGotoに関する多くの問題は、チームのコードレビューなどの開発プロセスで解決できます。
goto
同じ技術的な方法で、ジャンプがあるcontinue
、break
とreturn
。これらは同じように悪であると主張することもできますが、そうではありません。
GoチームがGotosを組み込んだ理由は、それが一般的なフロー制御プリミティブであるという事実が原因であると考えられます。さらに、彼らはうまくいけば、囲碁の範囲がばか安全な言語を乱用することを不可能にすることを除外すると結論付けました。
continue
、break
、そしてreturn
一つのキーの特定に非常に異なっている:彼らは唯一の「囲みスコープを残す」を指定します。彼らは奨励するだけでなく、開発者がコードの構造を検討し、構造化プログラミングプリミティブ(ループ、関数、スイッチステートメント)に依存することを明示的に要求します。goto
ステートメントの唯一の節約は、コンパイラのオプティマイザがタスクに達していないときにHLLでアセンブリを記述できることですが、これは可読性と保守性を犠牲にします。
setjmp
、longjmp
、goto
、そしてtry / except / finally
彼らの側に誤ることにしました注意してください。goto
、fwictは、事前「構造化プログラミング」制御フローに対する唯一の黙認です。