Я столкнулся с этим вопросом секунду назад, и я извлекаю часть материала оттуда: есть ли название для конструкции 'break n'?
Похоже, что это слишком сложный способ заставить людей дать команду программе выйти из двойного вложенного цикла for:
for (i = 0; i < 10; i++) {
bool broken = false;
for (j = 10; j > 0; j--) {
if (j == i) {
broken = true;
break;
}
}
if (broken)
break;
}
Я знаю, что в учебниках нравится говорить, что заявления goto - это дьявол, и я их совсем не люблю, но оправдывает ли это исключение из правила?
Я ищу ответы, которые касаются n-вложенных циклов.
ПРИМЕЧАНИЕ. Независимо от того, отвечаете ли вы «да», «нет» или где-то посередине, ответы совершенно не принимаются . Особенно, если ответ «нет», то предоставьте хорошую, законную причину (почему, в любом случае, это не слишком далеко от правил Stack Exchange).
coding-style
goto
Panzercrisis
источник
источник
for (j = 10; j > 0 && !broken; j--)
то вам не понадобитсяbreak;
оператор. Если вы переместите объявление вbroken
до того, как начнется внешний цикл, тогда, если это можно записать так, какfor (i = 0; i < 10 && !broken; i++)
я думаю, нетbreak;
необходимости.goto
: goto (C # Reference) - «Оператор goto также полезен для выхода из глубоко вложенных циклов».goto
фактически требуется в переключателе C # для перехода к другому случаю после выполнения любого кода внутри первого случая. Это единственный случай, когда я использовал goto.Ответы:
Очевидная потребность в операторе перехода возникает из-за того, что вы выбрали плохие условные выражения для циклов .
Вы утверждаете, что хотели, чтобы внешний цикл продолжался столько же, сколько
i < 10
самый внутренний, чтобы продолжался до тех порj > 0
.Но на самом деле это не то, что вы хотели , вы просто не указали циклам реальное состояние, которое вы хотели, чтобы они оценили, а затем вы хотите решить его, используя break или goto.
Если вы сообщаете петлям о своих истинных намерениях для начала , то не нужно делать перерывы или переходить к началу .
источник
i
в конце внешнего цикла, поэтому короткое замыкание приращения важно, чтобы код выглядел на 100% эквивалентным. Я не говорю, что в вашем ответе нет ничего правильного, я просто хотел указать, что немедленное прерывание цикла было важным аспектом кода.i
в конце внешнего цикла в вопросе OP.goto
(я уверен, что есть лучшие), даже если он породил вопрос, который, кажется, использует его как таковой, но чтобы проиллюстрировать основные действияbreak(n)
в языках, которые не ' не могу это поддержать.В этом случае вы можете преобразовать код в отдельную подпрограмму, а затем просто
return
из внутреннего цикла. Это сведет на нет необходимость вырваться из внешнего цикла:источник
i
после окончания внешнего цикла. Таким образом, чтобы действительно отразить этоi
является важной ценностью, здесьreturn true;
и такreturn false;
должно бытьreturn i;
.Нет, я не думаю, что это
goto
необходимо. Если вы напишите это так:Наличие
&&!broken
на обоих циклах позволяет вам выйти из обоих циклов, когдаi==j
.Для меня такой подход предпочтительнее. Условия цикла чрезвычайно ясно:
i<10 && !broken
.Работающую версию можно увидеть здесь: http://rextester.com/KFMH48414
Код:
Выход:
источник
broken
в своем первом примере вообще ? Просто используйте разрыв на внутренней петле. Кроме того, если вам абсолютно необходимо использоватьbroken
, зачем объявлять это вне циклов? Просто объявить его внутри вi
петле. Что касаетсяwhile
цикла, пожалуйста, не используйте это. Честно говоря, я думаю, что он может быть даже менее читабельным, чем версия goto.broken
используется, потому что я не люблю использоватьbreak
оператор (кроме случая переключения, но это все). Он объявляется вне внешнего цикла, если вы хотите прервать ВСЕ циклы, когдаi==j
. В общем, вы правы,broken
нужно только объявить перед самым внешним циклом, который он прервет.i==2
в конце цикла. Условие успеха также должно замкнуть приращение, если оно должно быть на 100% эквивалентно abreak 2
.broken = (j == i)
вместо if и, если язык позволяет, помещать прерванное объявление внутри инициализации внешнего цикла. Хотя трудно сказать эти вещи для этого конкретного примера, поскольку весь цикл не работает (он ничего не возвращает и не имеет побочных эффектов), и если он что-то делает, он, возможно, делает это внутри if (хотя мне все еще нравитсяbroken = (j ==i); if broken { something(); }
лучше лично)i
после окончания внешнего цикла. Другими словами, единственная действительно важная мысль - это когда именно она вырывается из внешнего цикла.Краткий ответ «это зависит». Я выступаю за выбор в отношении разборчивости и понятности вашего кода. Путь перехода может быть более разборчивым, чем изменение условия, или наоборот. Вы также можете принять во внимание принцип наименьшего удивления, руководство, используемое в магазине / проекте, и согласованность кодовой базы. Например, goto to switch или для обработки ошибок - обычная практика в кодовой базе ядра Linux. Также обратите внимание, что у некоторых программистов могут возникнуть проблемы с чтением вашего кода (либо возникшие с мантрой «goto is evil», либо просто не изученные, потому что их учитель так считает), и некоторые из них могут даже «судить вас».
Вообще говоря, переход к той же функции часто приемлем, особенно если прыжок не слишком длинный. Ваш сценарий использования вложенного цикла - один из известных примеров «не очень злого» перехода.
источник
В вашем случае, goto достаточно улучшения, которое выглядит заманчиво, но это не столько улучшение, сколько стоит нарушать правило против использования их в вашей кодовой базе.
Подумайте о вашем будущем рецензенте: ему / ей придется подумать: «Этот человек плохой кодер или это действительно тот случай, когда goto стоило того? Позвольте мне потратить 5 минут, чтобы решить это для себя или исследовать его на интернет «. С какой стати вы так поступаете со своим будущим кодером, если не можете использовать goto полностью?
В общем, этот менталитет применяется ко всему «плохому» коду и даже определяет его: если он работает сейчас и хорош в этом случае, но прилагает усилия для проверки его правильности, что в эту эпоху всегда будет делать goto, то не сделай это.
При этом, да, вы произвели один из чуть более острых случаев. Ты можешь:
Мне очень трудно создать случай, когда двойной цикл не настолько сплочен, что в любом случае он не должен быть его собственной рутиной.
Между прочим, лучшая дискуссия, которую я видел, - это « Завершенный код» Стива Макконнелла . Если вам нравится критически относиться к этим проблемам, я настоятельно рекомендую читать, даже прикрытие, несмотря на его необъятность.
источник
TLD; DR: нет конкретно, да вообще
Для конкретного примера, который вы использовали, я бы сказал «нет» по тем же причинам, на которые указывали многие другие. Вы можете легко преобразовать код в эквивалентно хорошую форму, что устраняет необходимость в
goto
.В целом, запрет на использование
goto
- это общность, основанная на понятной природеgoto
и стоимости его использования. Часть разработки программного обеспечения принимает решения о внедрении. Обоснование этих решений происходит путем сопоставления затрат с выгодами, и всякий раз, когда выгоды перевешивают затраты, внедрение оправдано. Противоречие возникает из-за различных оценок, как стоимости, так и выгоды.Дело в том, что всегда будут исключения, где
goto
оправдано, но только для некоторых из-за разных оценок. Жаль, что многие инженеры просто исключают методы целенаправленного невежества, потому что они читают это в Интернете, а не тратят время, чтобы понять, почему.источник
Я не думаю, что этот случай оправдывает исключение, так как это можно записать так:
источник