10

GoTo私は別のフォーラムにコードスニペットを投稿して助けを求めましたが、ステートメントを使用することはプログラミングの非常に悪い習慣であると人々は私に指摘しました。私は疑問に思っています:なぜそれは悪いのですか?

VB.NETで使用するための代替手段としてGoTo、一般的にはより良い方法と見なされるものはありますか?

ユーザーが生年月日を入力する必要がある以下のスニペットについて考えてみます。月/日付/年が無効または非現実的である場合は、ループバックしてユーザーにもう一度質問したいと思います。(私は整数のサイズをチェックするためにifステートメントを使用しています...これを行うためのより良い方法があれば、それも教えていただければ幸いです:D)

retryday:
    Console.WriteLine("Please enter the day you were born : ")
    day = Console.ReadLine
    If day > 31 Or day < 1 Then
        Console.WriteLine("Please enter a valid day")
        GoTo retryday
    End If
4

14 に答える 14

19

私は他の人とは異なり、GOTO自体がすべての悪ではないと言います。悪はGOTOの誤用から来ています。

一般に、GOTOを使用するよりも優れたソリューションがほとんどの場合ありますが、実際にはGOTOがそれを行う適切な方法である場合があります。

そうは言っても、あなたは初心者なので、GOTOが適切かどうかを判断することを許可されるべきではありません(ほとんどないため)。

私はあなたのコードをこのように書きます(私のVBは少し錆びています...):

Dim valid As Boolean = False

While Not valid
    Console.WriteLine("Please enter the day you were born: ")

    Dim day As String

    day = Console.ReadLine

    If day > 31 Or day < 1 Then
        Console.WriteLine("Please enter a valid day.")
    Else
        valid = True
    End If
End While

あなたがあなたのGOTOコードを取り、それを見ると、誰かが最初にあなたのコードにどのようにアプローチしますか?「うーん..retryday?これは何をしますか?これはいつ起こりますか?ああ、その日が範囲外の場合はそのラベルに移動します。わかりました。日付が有効で範囲内にあると見なされるまでループします。」 。

一方、私のものを見ると:

「ああ、有効になるまでこれを続けたい。日付が範囲内にあるときに有効だ。」

于 2010-04-23T17:27:47.647 に答える
6

http://xkcd.com/292/これはの標準的な意見だと思いますGoTo

代わりに、Do Untilループを試して使用してください。Do Untilループは常に1回実行され、ユーザーにプロンプ​​トを表示する必要があり、ユーザーが正しい情報を入力するまで続行しないようにする必要がある場合に最適です。

Sub Main()
    'Every time the loop runs, this variable will tell whether
    'the user has finally entered a proper value.
    Dim Valid As Boolean = False

    'This is the variable which stores the final number which user enters.
    Dim Day As Integer = 0
    Do Until Valid
        Console.WriteLine("Enter the day:")
        Dim DayStr As String = Console.ReadLine()

        If Not Integer.TryParse(DayStr, Day) Then
            Console.WriteLine("Invalid value! It must be a valid number.")
            Valid = False
        ElseIf (Day < 1) Or (Day > 31) Then
            onsole.WriteLine("Invalid day! It must be from 1 to 31.")
           Valid = False
        Else
           Valid = True
        End If
    Loop

    'blablabla
    'Do whatever you want, with the Day variable
End Sub
于 2010-04-23T17:20:51.487 に答える
2

コンストラクトはGOTOsphagettiコードを生成します。これにより、コードをトレースすることはほとんど不可能になります。

手続き型/関数型プログラミングは、はるかに優れたアプローチです。

于 2010-04-23T17:18:20.260 に答える
2

GoTo声明のメリット(またはむしろその欠如)についての質問は、このサイトで根強いものです。例については、ここをクリックしてください: GoToはまだ有害であると見なされていますか?

の代替案に関してはGoTo、提供されたスニペットでは、whileループがうまく機能します。おそらく次のようになります。

day = -1
While (day < 0)
   Console.WriteLine("Please enter the day you were born : ")
   day = Console.ReadLine
   If day > 31 Or day < 1 Then
     Console.WriteLine("Please enter a valid day")
      day = -1
   End If
End While
于 2010-04-23T17:25:34.240 に答える
1

gotoの使用は、何十年もの間悪い習慣と見なされてきました。おそらく、それは元のBASIC(Visual Basicより前)に対する反発でした。元のBASICには、whileループ、ローカル変数(グローバルのみ)、および(ほとんどのBASICバージョンでは)関数がパラメーターを受け取ったり値を返したりすることはできませんでした。さらに、機能は明示的に分離されていませんでした。RETURNステートメントを忘れた場合、制御は暗黙的に1つの関数から別の関数に落ちる可能性があります。最後に、コードのインデントは、これらの初期のBASICでは異質な概念でした。

元のBASICをしばらく使用した場合(私が行ったように)、グローバル変数とgotoをどこでも使用すると、大規模なプログラムが理解しにくくなり、細心の注意を払わずに、複雑な混乱に変わってしまうことに気付くでしょう。 "スパゲッティ"。WHILE..WENDループとSUBを備えたQBASICを学んだとき、私は決して振り返りませんでした。

ゴトスが少しでも傷つくとは思いませんが、コーダー文化では、彼らがどういうわけか悪であるという強い感覚が残っています。したがって、私は、不快な感性を避ける以外の理由で、gotosを避けます。時折、gotoが問題をきれいに解決することがあります(内側のループ内から外側のループを抜け出すなど)が、別の解決策によってコードが読みやすくなるかどうかを検討する必要があります(たとえば、外側のループを別の関数に入れて「内側のループで、gotoの代わりに「exitfunction」)。

私はおそらく100,000行のコードでC++プログラムを作成し、gotoを30回使用しました。一方、1,000を超える「通常の」ループと約10,000の「if」ステートメントがあります。

于 2010-04-23T21:07:49.540 に答える
1

GOTOはかなり政治的な問題です。GOTOの「解決策」は、関数、メソッド、ループなどの他の組み込みナビゲーション構造を使用することです。VBの場合、そのコードを実行するサブプロシージャを作成するか、Whileループに入れることができます。あなたはそれらの主題の両方をかなり簡単にグーグルすることができます。

于 2010-04-23T17:18:31.597 に答える
1

少し不格好ですが:

    Dim bContinue As Boolean

    Console.WriteLine("Enter a number between 1 and 31")

    Do
        Dim number As Integer = Console.ReadLine()
        If number >= 1 AndAlso number <= 31 Then
            bContinue = True
        Else
            Console.WriteLine("Please enter a VALID number between 1 and 31")
        End If
    Loop Until bContinue

「gotoland」の基本的なループも検討してください

        Dim i As Integer
startofloop1:

        Debug.WriteLine(i)
        i += 1
        If i <= 10 Then
            GoTo startofloop1
        End If

        i = 0

startofloop2:

        Debug.WriteLine(i * 2)
        i += 1
        If i <= 10 Then
            GoTo startofloop2
        End If

これが同等の機能です。

   For x As Integer = 0 To 10
        Debug.WriteLine(i)
    Next
    For x As Integer = 0 To 10
        Debug.WriteLine(i * 2)
    Next

どちらが読みやすく、エラーが発生しにくいですか?

于 2010-04-23T17:30:29.563 に答える
1

機能FTW!

さて、ここであなたのコードが本当にVB.Netであるかどうかはわかりません。なぜなら、いくつかの奇妙なタイプのものが進行しているからです(つまり、比較できる数値ではなく、をConsole.Readline返します)...String今のところタイプを忘れてください。

Console.Writeline("Please enter the day you were born : ")
day = Console.Readline()

While not ValidDate(day)
   Console.WriteLine("Please enter a valid day")
   day = Console.Readline()
End While

そして別に

Function ValidDate(day) As Boolean
  Return day > 31 Or day < 1
End Function

または、再帰とアーリーリターン構文を楽しむこともできます。;)

Function GetDate() As String
  Console.Writeline("Please enter the day you were born : ")
  day = Console.Readline()

  If ValidDate(day) Then Return day 'Early return

  Console.Writeline("Invalid date... try again")
  GetDate()
End Function
于 2012-09-25T18:13:47.407 に答える
0
While True
    Console.WriteLine("Please enter the day you were born : ")
    day = Console.ReadLine
    If day > 31 Or day < 1 Then
        Console.WriteLine("Please enter a valid day")
        Continue
    Else
        Break
    End If
End While
于 2010-04-23T17:17:39.857 に答える
0

GOTO決定構造やループなどの単純な組み込み言語構造を使用して、sで実行できるほとんどすべてのことを実行できます。GOTOステートメントは、多くの場合、厄介で理解できないスパゲッティコードになります。ループやifなどには、明確で、受け入れられ、理解できる使用法があります。

通常提案されているように、ダイクストラの「有害と考えられる」の声明を参照してください。

于 2010-04-23T17:19:14.310 に答える
0

多くの場合、有害と考えられる「Go-ToStatement」のダイクストラのアドバイスに従うことをお勧めします。

ドナルド・クヌースはダイクストラにかなりしっかりと答えました。この例は、彼の反例の1つの最新バージョンです。個人的には、これに遭遇したときに内部ブレークを使用して無限ループを作成しますが、GOTOステートメントを作成するまれなケースが他にもいくつかあります。

私にとって最も一般的なものは、深くネストされたループとこのパターンから抜け出すことです。

ContinueTry:
   Try
        'Worker code
   Catch ex as IO.IOException
        If MessageBox.Show(...) = DialogResult.Retry Then Goto ContinueTry
        Throw
   End Try

また、遷移を提供するgotoステートメントを持つ大規模な有限状態マシンの2つのケースがあります。

于 2010-04-23T17:42:32.313 に答える
0

「本による」オオカミが反対票を投じても、私は私のものを投げます。ご覧ください:ループと関数をサポートする言語で「goto」を使用することはこれまでに有利ですか?もしそうなら、なぜですか?

于 2014-10-16T13:58:32.583 に答える
0

ここにいる他のみんなに同意する必要があります。GOTO自体は悪ではありませんが、それを誤用すると確かにあなたの人生は悲惨なものになります。選択できる制御構造は他にもたくさんあり、適切に作成されたプログラムは通常、gotoなしでほとんどすべての状況を処理できます。そうは言っても、私は約15,000行を積み上げるプログラムの完成間近の段階にあり、GOTOステートメントを1つだけ使用しました(これを置き換える可能性があります)。私が扱った過去12ほどのプログラムでGOTOを使用したのはこれが初めてです。しかし、この例では、コンパイラエラーを取り除きました(同じSub内で異なるIf構造内でMe.Close()を2回使用します。抑制できたはずですが、ラベルを挿入して1つのMe.Close()を次のように置き換えました。 GoTo CloseLabel)。私を必要とするより多くのインスタンスに遭遇し始めた場合。このSub内のClose()は、Me.Close()を独自のサブに配置し、プログラムを閉じる結果となるIf構造体または他のループからそのサブを呼び出す可能性があります...前述のように、代替手段ですが、場合によっては、非常にまれに、控えめに、戦略的に使用する場合でも、GoToが役立つ場合があります。スパゲッティコードに注意してください、それはまばたきの混乱です笑

于 2016-05-09T13:03:38.600 に答える
-2

あなたのコードは大丈夫です。簡潔で明確です。同じことを行う追加の変数と異なる動詞でジョブを50%から200%膨らませるよりも優れています。

論理ブロックの最初または最後まで後方または前方にスキップするだけの場合は、go(to)を実行します。「Loop」または「Endwhile」はまだgotoですが、宛先が暗黙指定されています。唯一の利点は、コンパイラーが2つのループをクロスパスにすることを阻止することですが、gotoのペアではできません。gotoを使用するときは、ストリームを横断しないでください。それは悪いことです。-スペングラー博士

私の他のペットピーブは「1つの入口、1つの出口」ルールです。もちろん、アセンブラで記述している場合を除いて、入口は1つしかありません。しかし、「1つの出口」のルールは愚かです。それは、コードを右マージンから外すネストされた境界チェックの束につながるだけです。ルーチンの先頭ですべてのパラメーターをテストし、それらが違法である場合は「exitsub」を実行する方がはるかに明確です。何がより理にかなっていますか?

if badparam then
  log error
  exit sub
  endif

if badparam2 then
  log error2
  exit sub
  endif

do stuff

またはこれ?

if goodparam then
  if goodparam2 then
    do stuff
  else
    log error2
    endif
else
  log error 
  endif 

6つの境界チェックがあり、「もの」が60行で、小さなビットに分割できない場合、2番目の方法は、それを維持する必要がある人にとっては悪夢になります。すべての例外処理を最後まで延期するよりも、実行していたこと(例外のチェック)を終了することをお勧めします。

私の$0.02

于 2010-04-23T20:17:20.427 に答える