«Гото» это плохо?

После некоторого изучения вопроса о том, как прорваться через вторичный цикл

while (true) { // Main Loop for (int I = 0; I < 15; I++) { // Secondary loop // Do Something break; // Break main loop? } } 

большинству людей рекомендуется называть функцию ‘goto
Как выглядит следующий пример:

 while (true) { // Main Loop for (int I = 0; I < 15; I++) { // Secondary Loop // Do Something goto ContinueOn; // Breaks the main loop } } ContinueOn: 

Однако; Я часто слышал, что утверждение «goto» – это плохая практика. Рисунок ниже прекрасно иллюстрирует мою мысль: Серия найдена

Так

  • Насколько плохое утверждение goto действительно и почему?
  • Есть ли более эффективный способ разбить основной цикл, чем использовать оператор ‘goto’?

РЕДАКТИРОВАТЬ:

Насколько плохое утверждение goto действительно и почему?

Это зависит от конкретной ситуации. Я не могу вспомнить, когда я нашел, что код стал более читаемым, чем рефакторинг. Это также зависит от вашего личного взгляда на читаемость – некоторые люди не любят его больше, чем другие, как видно из других ответов. (В качестве точки интереса он широко используется в сгенерированном коде – весь код async / await на C # 5 основан на эффективном множестве gotos).

Проблема состоит в том, что ситуации, когда goto обычно используются, как правило, являются такими ситуациями, когда рефакторинг помогает в любом случае – в то время как goto придерживается решения, которое становится более сложным, поскольку код становится более сложным.

Есть ли более эффективный способ разбить основной цикл, чем использовать оператор ‘goto’?

Абсолютно. Извлеките свой метод в отдельную функцию:

 while (ProcessValues(...)) { // Body left deliberately empty } ... private bool ProcessValues() { for (int i = 0; i < 15; i++) { // Do something return false; } return true; } 

Я вообще предпочитаю делать это за введение дополнительной локальной переменной, чтобы отслеживать «я закончил», хотя это, конечно, будет работать.

Насколько плохое утверждение goto действительно и почему?

Это действительно плохо для всех обычных причин. Это превосходно отлично при эмуляции помеченных контуров на языках, которые их не поддерживают.

Замена его функциями во многих случаях будет иметь логику разброса, которая действительно должна читаться как одна и та же единица. Это затрудняет чтение. Никто не любит следовать следам функций, которые на самом деле ничего не делают, пока в конце путешествия, когда вы немного забыли, откуда вы начали.

Замена его с помощью булевых элементов и кучей дополнительных ifs и breaks просто неудобно и затрудняет выполнение реальных намерений, таких как любой шум.

В java (и javascript) это вполне приемлемо (обозначенные петли):

 outer: while( true ) { for( int i = 0; i < 15; ++i ) { break outer; } } 

В C # это выглядит как очень близкий эквивалент:

 while( true ) { for (int I = 0; I < 15; I++) { goto outer; } } outer:; 

Из-за слова goto , который имеет психологический эффект от того, чтобы заставить людей отказаться от своего здравого смысла и заставить их связывать xkcd, независимо от контекста.

Есть ли более эффективный способ разбить основной цикл, чем использовать оператор 'goto'?

В некоторых случаях этого нет, поэтому другие языки предоставляют помеченные циклы, а C # - goto . Обратите внимание, что ваш пример слишком прост, и он делает работу не слишком плохим, потому что они адаптированы к этому примеру. Фактически, я мог бы просто предложить следующее:

  for (int I = 0; I < 15; I++) { break; } 

Как насчет этого:

 int len = 256; int val = 65536; for (int i = 0; i < len; i++) { for (int j = 0; j < len; j++) { if (i + j >= 2 * val) { goto outer; } val = val / 2; } } outer:; 

Это все еще хорошо для вас:

 int len = 256; int val = 65536; for (int i = 0; i < len; i++) { if (!Inner(i, ref val, len)) { break; } } private bool Inner(int i, ref int val, int len) { for (int j = 0; j < len; j++) { if (i + j >= 2 * val) { return false; } val = val / 2; } return true; } 

Я категорически не соглашусь со всеми другими ответами здесь. Код, который вы представляете с помощью goto , не имеет ничего плохого в этом. Существует причина, по которой C # имеет инструкцию goto , и именно для этих типов сценариев вы описываете.

goto просто имеет отрицательную стигму, потому что в 1970-х годах и раньше люди писали бы ужасный, совершенно не поддающийся оценке код, где stream управления прыгал повсюду из-за goto . C # ‘s goto даже не позволяет переходить между методами! Но до сих пор существует иррациональная стигма.

По моему мнению, нет абсолютно ничего плохого в использовании «современного» goto для выхода из внутреннего цикла. «Люди альтернативы» всегда оказываются более сложными и трудными для чтения .

Обычно предполагается, что методы могут использоваться повторно . Создание целого отдельного метода для внутренней части цикла, который только когда-либо вызывается из этого одного места, и где реализация метода может оказаться в некотором отдаленном месте в исходном коде, не является улучшением.

Такое глупое упражнение, чтобы избежать goto в основном эквивалентно политической корректности, но в мире программирования.

Я согласен с большинством ответов о том, как плохо получается.

Мое предположение, чтобы избежать goto, делает что-то вроде этого:

 while (condition) { // Main Loop for (int i = 0; i < 15; i++) { // Secondary loop // Do Something if(someOtherCondition){ condition = false // stops the main loop break; // breaks inner loop } } } 

Я иногда использую «goto», и я нашел, что он выглядит хорошо, как пример выше;

 bool AskRetry(Exception ex) { return MessageBox.Show(you know here...) == DialogResult.Retry; } void SomeFuncOrEventInGui() { re:try{ SomeThing(); } catch (Exception ex) { if (AskRetry(ex)) goto re; else Mange(ex); // or throw or log.., whatever... } } 

Я знаю, что вы можете сделать то же самое рекурсивно, но кто заботится об этом, просто работает, и я использую.

Мой коллега (у которого есть 15 лет + в программировании прошивки), и я все время использую goto. Однако мы используем его только для обработки исключений !! Например:

 if (setsockopt(sd,...)<0){ goto setsockopt_failed; } ... setsockopt_failed: close(sd); 

Насколько мне известно, это лучший способ справиться с исключениями в C. Я считаю, что я тоже работаю на C #. Кроме того, я не единственный, кто так думает: примеры хороших gotos в C или C ++

Перейти к опасным, помимо других проблем. Собственная компиляция Goto на каком-либо языке принимает C #, например, несмотря на то, что в этой функции нет операторов возврата, это будет скомпилировано.

 public int Test() { goto one; one: { goto one; } } 

Лично мне нравится думать о goto, как «goto ведет к аду» … и во многих отношениях это верно, поскольку это может привести к очень неудержимому коду и действительно плохой практике.

При этом он по-прежнему используется по какой-либо причине, и при его использовании его следует использовать экономно, если нет другого решения. Языки OO поддаются на это не очень.

Единственное, что я когда-либо видел в этих днях, – это обфускация … пример goot использования goto для создания кода из ада, поэтому люди будут отстранены от попытки понять это!

Некоторые языки зависят от эквивалентных ключевых слов. Например, в x86 году у вас есть такие ключевые слова, как JMP (Jump), JE (Jump if Equal) и JZ (Jump if Zero). Это часто требуется на языке ассемблера, поскольку на этом уровне нет OO, и есть несколько других способов перемещения в приложении.

AFAIK … держитесь подальше от него, если АБСОЛЮТНО НЕОБХОДИМО.

  • foreach vs someList.ForEach () {}
  • использование ярлыков в java без "петель"
  • jQuery AJAX вызывает цикл
  • Как сделать бесконечную анимацию jquery?
  • JFreechart Loop через сектора полярных диаграмм
  • Макрос Vba для копирования строки из таблицы, если значение в таблице соответствует условию
  • Неправильно ли использовать break для выхода из цикла в Java?
  • Прокрутка файлов в папке в matlab
  • Java: бесконечный цикл с использованием Scanner in.hasNextInt ()
  • Вызов удаления в цикле foreach в Java
  • Каков наиболее эффективный / быстрый способ циклического преобразования строк в VBA (excel)?
  • Interesting Posts

    Передайте пользовательский объект в ASP.NET Webmethod из jQuery, используя JSON

    LibreOffice на OS X: работает софит, не говоря о Info.plist или не имеет NSPrincipalClass в Info.plist

    Добавление пространства между столбцами в ggplot2

    Bash: указание переменных среды для эха в командной строке?

    Ubuntu X11: возможно ли открыть приложение X в другом сеансе пользователей

    Как получить имя ресурса из идентификатора ресурса

    Как написать стиль в текст ошибки EditText в Android?

    Будет ли Hibernate очищать мой обновленный постоянный объект при вызове session.close () с помощью FlushMode.AUTO?

    Удаленный рабочий стол от Win10 -> Windows Server 2016 медленный, но быстрый наоборот

    Поиск в Google «перейти к результатам»

    Как восстановить значок жесткого диска? Windows 7

    процент на y lab в гранжевом барграфе ggplot?

    Использование оператора и IDisposable.Dispose ()

    Как установить лимиты для осей в графиках ggplot2 R?

    Доступны ли значения, определенные в MANIFEST.MF программно?

    Давайте будем гением компьютера.