Прерывание цикла for с помощью break это плоxo?
И снова я со своей книгой «Для про». Почему в цикле for не рекомендуется прерывание с помощью break ? Как же тогда это сделать?
![]()
Мне этот совет кажется достаточно странным.
Представьте себе, что вы можете определить условие выхода только после какой-то работы. Например:
Этот код говорит сам за себя: если мы нашли плохой тип файла, обработку завершаем.
Другие методы, например, присваивание специального значения переменной цикла или проверка специального флага «а не нужно ли нам завершить обработку вотпрямща», кажутся мне искусственными, костыльными путями сказать, что вы хотите просто завершить обработку в той точке, где стоит break .
В хорошем языке вы пишете то, что думаете, а не пытаетесь сказать это хитрыми косвенными методами.
Так что совет не использовать break я оставлю на совести автора книги. Этот совет мне кажется вредным.
Другое дело, что не стоит использовать break бесконтрольно, нужно всё время заботиться о читаемости кода. Иначе из полезного инструмента он превратится во вредный.
Мысли вслух
В общении с коллегами — учителями информатики — я много раз сталкивался с твёрдым убеждением, что использование оператора break для досрочного выхода из цикла — это «неграмотно», «грязный хак», «не соответствует принципам структурного программирования» и вообще «я своим ученикам такое не зачту». В то же время общение с профессиональными программистами показывает, что такой прием на практике применяется очень часто, потому что это удобно и в большинстве случаев делает программу более понятной.
Такой «разброд» имеет совершенно объяснимые причины. Большинство преподавателей, с одной стороны, когда-то заучили, что структурное программирование — это хорошо, а любое отступление от него — это плохо. С другой стороны, сами они уже фактически отошли от промышленного программирования: я могу на пальцах одной руки пересчитать знакомых (в том числе и по Интернету) учителей информатики, которые сами написали что-то стóящее. Таким образом, наблюдаем закон Дж.Б. Шоу в действии.
Попробуем разобраться в сути вещей. Оператор break — это фактически оператор перехода, знаменитый GOTO, который в 1970-е годы был морально уничтожен, прежде всего, стараниями «отца структурного программирования» Эдсгера Дейкстры [1]. Однако сами «отцы» хорошо понимали, что программа без GOTO ещё не становится автоматически структурной программой. Поэтому появилось на свет эссе Дональда Кнута «Структурное программирование с операторами GOTO» [2]. Кнут писал (перевод мой):
«Другими словами, мы не должны просто удалять операторы GOTO из-за того, что сейчас модно это делать; присутствие или отсутствие операторов GOTO — это не главный вопрос. Истинная цель состоит в том, чтобы формулировать наши программы таким образом, чтобы их было легко понимать.»
Посмотрим, как обстоит дело с пониманием программ, содержащих циклы с операторами break и сравним их с программами, где операторов break умышленно избегают.
Пример 1. С клавиатуры вводятся числа, ввод заканчивается числом 999. Вычислить сумму введенных чисел.
Вот решение с использованием break:На взгляд автора, этот алгоритм очень хорошо соответствует словесному описанию: «строим цикл, выход из которого происходит при получении числа 999».
Теперь посмотрим на «кошерные» альтернативы. Нужно как-то выполнить те же действия (то есть, выйти из цикла при получении числа 999), не используя оператор выхода из цикла.
Во-первых, можно поставить условие цикла x <> 999, но при этом нужно будет инициализировать переменную x до цикла каким-то «магическим числом», отличным от 999, например, 1 (или 998 :-). Программист, который будет разбираться в таком коде через некоторое время, спасибо вам не скажет. Кроме того, вторую часть тела цикла придется взять в условный оператор, а эта вторая часть может быть достаточно большой. Читабельность явно не повышается. Зато программа «структурная», можно «взять с полки пирожок». :-)Заметим, что число 999 появляется в программе дважды: в заголовке цикла и в условии в теле цикла, что само по себе уже нехорошо.
Можно вынести оператор Readln за цикл, продублировав его в теле цикла:На взгляд автора, при этом два оператора ввода, выполняющие одну и ту же функцию, «размывают» логику программы и не добавляют ей «прозрачности». Кроме того, вместо Readln в других ситуациях может стоять целая группа операторов, и тут уже дублирование будет выглядеть совсем некрасиво.
Кроме того, можно ввести логическую переменную (флаг), которой присваивается истинное значение при получении числа 999:Но тут нужно вспомнить о «бритве Оккама» — не плоди лишних сущностей. И ещё — любое усложнение системы, как правило, снижает её надежность.
Еще один вариант — перейти на цикл с постусловием:Во-первых, как и в одном из предыдущих вариантов, здесь два раза всплывает число 999. Во-вторых, вторую часть тела цикла снова нужно помещать в условный оператор. В-третьих, читать программы с циклами repeat — это сущее наказание: встретив слово repeat, судорожно пытаемся найти соответствующий until с условием, без этого всё вообще непонятно. Потом опять нужно смотреть наверх: что же там в теле цикла.
Можно, конечно, и так :-):Но по сути это то же самое, что и break. Использовать здесь исключения — всё равно, что гвозди микроскопом забивать.
Рассмотрим еще один пример.
Пример 2. Найти в массиве A[1..N] элемент, равный X, или сообщить, что такого элемента нет.
Решение с помощью break:Как и для первого примера, программа с break почти дословно повторяет словесное описание идеи решения: «просматриваем все элементы массива с первого до последнего; как только нашли нужный элемент, запоминаем его номер и выходим из цикла».
Вот альтернатива без break:Теперь представим себе, что будет, если в трансляторе включена проверка выхода за границы массива, логические выражения вычисляются полностью и элемента, равного X, в массиве нет: программа вылетит в результате обращения за пределы массива.
Вот еще вариант, с логической переменной:Какая программа понятнее, каждый решает сам. 🙂
- Оператор break есть практически во всех современных языках программирования. «Значит, это кому-нибудь нужно!»
- Это инструмент, который нужно использовать в соответствии с его назначением.
- Само по себе наличие или отсутствие оператора break ничего не говорит о том, грамотно ли написана программа; задача состоит в том, чтобы сделать ее наиболее понятной и «прозрачной».
- Использование оператора break относится к так называемым «структурным» переходам [3], то есть к переходам вперёд в пределах того же модуля, что не нарушает принципы структурного программирования.
Пример 3. В цикле обрабатываются все элементы массива A[1:N]. Для каждого из них сначала выполняются операторы S1, S2, . SN, в результате вычисляется некоторое значение x. Если получено значение x = 1, нужно выполнить еще операторы T1, T2, . TM, а в противном случае перейти к следующему элементу.
«Классическое» решение выглядит так:Вроде бы всё хорошо. Но мы потеряли «локальность»: при достаточно длинном теле условного оператора нужно еще «сканировать» цикл до конца, проверяя, не выполняются ли какие-то действия в том случае, когда x <> 1. А эту проблему может элегантно решить continue:Здесь уже точно ясно, что при x <> 1 никаких дополнительных операций не происходит. По мнению автора, такой вариант более «прозрачен» и, по крайней мере, не хуже предыдущего.
Остается еще один «смежный» вопрос: можно ли писать подпрограммы с несколькими выходами? Давайте посмотрим пример рекурсивной процедуры.
Пример 4. Разработать процедуру, которая выводит на экран решение задачи «Ханойская башня» [4].
Рекурсивное решение этой задачи хорошо известно, одна из реализаций выглядит так:Здесь n — количество дисков, которые нужно перенести; k — номер начального стержня и m — номер конечного стержня.
И все было бы хорошо, но тут нарушен ещё один принцип, который стал «священной коровой» ортодоксального структурного программирования: процедура имеет (увы 🙂 два выхода, один естественный, и второй — по признаку окончания рекурсии.
Можно ли было обойтись без этого? Да, можно, «упаковав» все тело процедуры внутрь условного оператора:Но тут мы опять теряем локальность — при достаточно длинном тексте процедуры нужно еще посмотреть, не выполняются ли какие-то действия после условного оператора. Да и не совсем понятно, зачем добавлять лишний уровень вложенности. «Не плоди лишних сущностей». По мнению автора, первое приведенное решение более понятное и более красивое.
Пример 5. Разработать функцию, которая определяет, если ли в квадратной матрице элемент, равный заданному значению.
Будем предполагать, что введен тип данныхТогда функцию можно написать так:Здесь оператор exit фактически выполняет роль break для вложенного цикла. С формальной точки зрения у функции два выхода. В общем, «я своим ученикам никогда такое не зачту» — уже слышу я от учителей информатики.
А давайте подумаем, какие альтернативы? Можно вот так:Но тут вообще «криминал» — метка и goto! Хотя по сути ничего не изменилось, тот же выход из вложенного цикла.
Конечно, здесь можно использовать исключение:Но ведь это далеко не «исключительная ситуация», поэтому по смыслу исключения здесь всё-таки не особо уместны. Кроме того, нужно учитывать, что при обработке исключений выполняется большое число машинных команд, что снижает эффективность программы.
Любителей «чистого» структурного программирования наверняка устроит такой вариант решения:Но, к сожалению, по эффективности он не может составить конкуренцию предыдущим, так как в любом случае рассматриваются все N 2 элементов массива, даже если элемент A[1,1] равен X.
Эта статья, прежде всего, о том, что любые идеи и принципы нужно воспринимать в контексте конечной цели. Одна из основных целей концепции структурного программирования — повысить читаемость программ и за счёт этого облегчить их отладку, тестирование и сопровождение. Поэтому применение операторов break, continue и exit нельзя считать отступлением от структурного программирования, если это не ухудшает читаемость программы и не приводит к запутыванию логики алгоритма.
В то же время попытки избавиться от этих операторов (для того, чтобы формально соблюсти «классические правила») могут привести к ухудшению читаемости программы.
- Dijkstra E.W., Go To Statement Considered Harmful // Communications of the ACM, Vol. 11, No. 3, March 1968, pp. 147-148. (PDF)
- Knuth D.E. Structured Programming with GO TO Statements // ASM Computing Surveys. 1974. 6(4). P.261-301. (HTML, PDF)
- Непейвода H.H., Скопин И.Н. Основания программирования. — Москва-Ижевск: Институт компьютерных исследований, 2003. (PDF)
- Гарднер М., Математические головоломки и развлечения. — М.: Мир, 1999.
Комментарии: 23:
По моему опыту, брейк совершенно незаменим в случае, если нужно обработать исключительную ситуацию в схемах большой вложенности. Он существенно повышает читаемость в тех местах, где использование try except finally не критично.
На мой взгляд, страх break — это проблемы тех учителей, которые его запрещают. В ВУЗе потом приходится переучивать. Замечу, что ни один из студентов не смог достойно объяснить, почему break, который запрещал учитель, это плохо.
Я вот усугублю: найти элемент в матрице:
IsFound := False;
for i:=1 to n do
for j:=1 to n do
if a[i,j]=x then
begin
IsFound := True;
goto en;
end;
en:
Предложите лучший вариант 🙂
>> Предложите лучший вариант 🙂
Попробую. 🙂
type matr = array[1..N,1..N] of integer;
function FindMatr(A: matr; X: integer): boolean;
var i, j: integer;
begin
Result := True;
for i:=1 to N do
for j:=1 to N do
if A[i,j] = X then Exit;
Result := False;
end;
Ой, мерзость какая!
Exit — это еще хуже чем break!
break хоть из цикла выходит, а эта сразу из процедуры!
> Ой, мерзость какая!
Да нет, это ведь то же самое! Фактически, в данном случае Exit = break из вложенного цикла. Или GOTO, который вы предложили применить.
Это я неудачно шучу так. Просто без exit и goto этот пример вообще безобразно программируется.
Кстати, еще про continue надо поговорить до кучи. Можно, конечно. и без него, но есть ли случаи, когда с ним — лучше?
По поводу continue — это ведь тот же goto. Думаю, что вот этот случай оправдывает его использование, если T — достаточно большой блок операторов:
for i:=1 to N do begin
x := S(. );
if not Good(x) then continue;
T;
end;
Еще, как верно заметил автор первого комментария, использование try/except для обработки исключений — стандартная конструкция современных языков. Обрабатывать ошибки по-другому — нарушает многие каноны хороших программ. А разве переход от места возникновения исключения на обработчик исключения вверх на несколько подпрограмм — это не аналог break, только гораздо более махровый? Может, указанные Вами в статье учителя хотят и обработку исключений запретить?
Вопрос серьёзный: без break можно обойтись, но как обойтись без обработки исключений?
Решение первой задачи без Break:
s := 0;
Readln(x);
while x<>999 do begin
s := s + x;
Readln(x);
end;
> Решение первой задачи без Break:
Я знаю про это решение, но мне очень не нравится, что дважды используется оператор Readln. Это "размазывает" логику и делает программу менее понятной.
> как обойтись без обработки исключений?
Теоретически можно. Раньше ведь обходились, до начала 90-х. Коды возврата из функций.
Возвращаясь к решению первой задачи без Break: мне, напротив, это решение кажется наиболее логичным, естественным, поскольку в заголовке цикла сформулировано простое и понятное условие завершения, а Readln(x)перед циклом можно сравнить с инициализацией счетчика, которую мы делаем при замене цикл for на while
> Возвращаясь к решению первой задачи без Break: мне, напротив, это решение кажется наиболее логичным
Это дело вкуса, конечно. Да и речь, собственно, не о том. Мысль состоит в том, что решение с break, по крайней мере, ничем не хуже решения без break, и часто выглядит значительно понятнее. Вместо того же Readln могут быть совершенно другие операторы.
О первой задаче. А если так:
s:=0;
x:=0;
while x<>999 do
begin
s := s+x;
Readln(x)
end;
> О первой задаче. А если так:
Это ведь тоже искусственно. При чтении кода сразу возникает вопрос: "А почему в x записываем 0"? И потом: "А почему еще ничего не ввели, а уже суммируем?"
Понятность повышается? Нет.
To break or not to break. 🙂
Если уж приравнивать break к goto — то нужно все операторы управления процессом выполнения объявить вне закона — исключения, например. Что, конечно же, недопустимо по практическим соображениям.
Я бы немного переформулировал Кнута. Думаю, есть определенная неточность перевода с английского. Простота (simplicity) это в смысле программирования скорее "очевидность".
По возможности, нужно избавить программы от неочевидных и нестандартных ходов, пусть даже это и рождает некоторый оверхед в плане объема кода или его оптимальности.
Давно хотел спросить, хотя это и не очень в теме этого поста. Что вы думаете об использовании в обучении программированию сред типа Squeak (Smalltalk)? Если отвлечься от методических требований, конечно.
Вставлю свои 5 копеек.
Структурная конструкция цикла предполагает, что вход сверху, а выход — исключительно снизу.
В этом плане конструкция цикла представляет собой неделимый "кирпич", который можно "таскать" по коду "куда угодно". И я об этом не задумываюсь.
Если же в ней есть выход из середины — она уже не является таким "монолитом", я должен разобрать логику этого выхода.
На эту тему:
http://www.oberoncore.ru/wiki/%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BF%D1%80%D0%BE%D0%BC%D1%8B%D1%88%D0%BB%D0%B5%D0%BD%D0%BD%D0%BE%D0%B3%D0%BE_%D1%86%D0%B8%D0%BA%D0%BB%D0%B0
— здесь цикл с break-ами трансформирован в структурную форму (кстати, автор цикла с брейками — из очень солидной компиляторной компании из Сибири и очень спорил "за брейк").
В конце статьи разобраны убедительные аргументы против брейка (о том, КАК думает программист, привыкший анализировать свойства программы в терминах утверждений и почему такому программисту очень не хочется читать цикл построчно в поисках брейка и "гонять его в уме").
Также в эту тему статья "Базовые паттерны циклов":
http://www.oberoncore.ru/wiki/%D0%BF%D0%B0%D1%82%D1%82%D0%B5%D1%80%D0%BD%D1%8B_%D1%86%D0%B8%D0%BA%D0%BB%D0%BE%D0%B2
Вот на сходную тему — о том, почему могут быть плохи return-ы из середины процедуры:
http://forum.oberoncore.ru/viewtopic.php?p=42554#p42554
Также в вышеприведённой статье "Базовые паттерны циклов" прошу обратить внимание на то, почему повторение "лишней" инструкции до цикла — не громоздко, а как раз логично.
Потому что стоит заметить, что такая инструкция выполняется n+1 раз, в отличие от остальных, которые выполняются n раз. И совершенно логично такой дополнительный раз вынести за цикл.
Для иллюстрации цикл покраски забора из N секций и, разумеется, N+1 столбов:
Покрасить столб;
ЦИКЛ N раз:
Покрасить секцию;
Покрасить столб
КОНЕЦ
— вот яркая иллюстрация. Пытаться засунуть покраску "лишнего" столба внутрь цикла — это противоестественное занятие, простие.
Это же касается циклов в духе:
for.
.
if НАШЛИ then
что-то делаем; break
end if
end for
Никого не коробит, что внутри цикла оказалось однократное действие, которое, вообще-то, должно находится логичным образом после цикла? 🙂
Всё это, мне кажется, от недостаточного внимания к логическим свойствам программ. От отношения к ним, как "литературному произведению". "Лишь бы машина понимала". Более продвинутое: "ну и лишь бы читателям потом тоже было нормально". Но никто не доходит до "лишь бы обладало понятными, гарантированными, доказуемыми свойствами".
Посмотрел статью поподробнее.
Варианты с логическими флагами просто ужасны — и полностью, конечно, дискредитируют идею "программировать без брейк".
Но, Константин Юрьевич, Вы же сами привели чистый классический вариант линейного поиска (который обязан знать и использовать любой образованный программист, имхо):
[ЦИТАТА]
Вот альтернатива без break:
nX := 1;
while (nX <= N) and (A[nX] <> X) do
Inc(nX);
if nX > N then
writeln('Не нашли!')
else writeln('nX = ', nX);
[/ЦИТАТА]
И что же Вас беспокоит:
[ЦИТАТА]
Теперь представим себе, что будет, если в трансляторе включена проверка выхода за границы массива, логические выражения вычисляются полностью и элемента, равного X, в массиве нет: программа вылетит в результате обращения за пределы массива.
[/ЦИТАТА]
Беспокоит опция из тех дремучих времён, когда создаатели некоторых компиляторов ещё не знали, что сокращённое вычисление — это ОБЯЗАТЕЛЬНЫЙ И БЕЗАЛЬТЕРНАТИВНЫЙ режим, потому что в другом режиме "культурно по-Дейкстре" программировать невозможно?
Это выключающий такую опцию должен думать о том, что он рушит любую нормально написанную программу, имеющую хоть один линейный поиск.
Где сегодня Вы найдёте такую опцию?
Единственное, бывает, что в языках введено по две логических операций — полная и сокращённая (and и cand, or и cor) — так сделано, например, в Аде.
С уважением.
Простите за некоторый "напор", но на Вас большая ответственность, потому что Вас читают многие-многие 🙂
а как с постусловием решить это? Дан массив действительных чисел. Среди них есть равные. Найти первый max элемент и заменить ТОЛЬКО его нулем. Подробно, если не сложно. Заранее преблагодарен.
> Дан массив действительных чисел. Среди них есть равные.
> Найти первый max элемент и заменить ТОЛЬКО его нулем.
Зачем тут цикл с условием? Почему не так:
nMax := 1;
for i:=1 to N do
if A[i] > A[nMax] then
nMax := i;
A[nMax] := 0;
Это плохая практика, чтобы использовать перерыв в цикле for? [закрытый]
это плохая практика, чтобы использовать break сообщении внутри for loop?
скажем, я ищу значение в массиве. Сравнить внутри цикла for и когда значение найдено, break; для выхода из цикла for.
это плохая практика? Я видел альтернативу: определите переменную vFound и установите его в true, когда значение будет найдено и проверьте vFound на for условие. Но нужно ли создавать новый переменная как раз для этой цели?
Я спрашиваю в контексте обычного цикла C или C++ for.
P. S: The руководство по кодированию Мисра советуют не использовать перерыв.
19 ответов:
здесь много ответов, но я еще не видел этого:
большинство «опасностей», связанных с использованием break или continue в цикле for отрицаются, если вы пишете аккуратные, легко читаемые циклы. Если тело вашего цикла занимает несколько длин экрана и имеет несколько вложенных подблоков, да, вы можете легко забыть, что некоторый код не будет выполнен после перерыва. Если, однако, цикл короткий и до точки, цель инструкции break должна быть очевидный.
если цикл становится слишком большим, вместо этого используйте один или несколько хорошо именованных вызовов функций в цикле. Единственная реальная причина избежать этого-это обработка узких мест.
нет, перерыв-это правильное решение.
добавление логической переменной усложняет чтение кода и добавляет потенциальный источник ошибок.
вы можете найти все виды профессионального кода с инструкциями «break» в них. Это совершенно имеет смысл использовать это всякий раз, когда это необходимо. В вашем случае этот вариант лучше, чем создание отдельной переменной только с целью выхода из цикла.
используя break а также continue на for цикл прекрасно.
Это упрощает код и повышает его читаемость.
далеко от плохой практики, Python (и других языков?) продлил for цикл структура так часть его будет только выполняется, если цикл не break .
выход:
эквивалентный код без break и что пригодится else :
общее правило: если следование правилу требует от вас сделать что-то более неудобное и трудное для чтения, а затем нарушить правило, затем нарушить правило.
в случае цикла, пока вы не найдете что-то, вы столкнетесь с проблемой различения найденного и не найденного, когда вы выходите. То есть:
Итак, вы можете установить флаг или инициализировать «найденное» значение в null. Но
вот почему в целом я предпочитаю продвигать свои поиски функции:
Это также помогает разгадать код. В основной строке «найти» становится одним утверждением, и когда условия сложны, они записываются только один раз.
Это зависит от языка. Хотя вы можете проверить логическую переменную здесь:
это невозможно сделать при итерации по массиву:
В любом случае, break сделает оба кода более читабельными.
нет ничего изначально неправильного в использовании инструкции break, но вложенные циклы могут запутаться. Для улучшения читаемости многих языков (по крайней мере Java делает) поддержка ломать к ярлыкам которые значительно улучшат удобочитаемость.
Я скажу, что операторы break (и return) часто увеличиваются цикломатическая сложность что затрудняет доказательство того, что код делает правильную вещь во всех случаях.
Если вы рассматриваете используя перерыв при повторении последовательности для некоторого конкретного элемента, вы можете пересмотреть структуру данных, используемую для хранения данных. Использование чего-то вроде набора или карты может обеспечить лучшие результаты.
перерыв является полностью приемлемым заявлением для использования (так что дальше, кстати). Все дело в удобочитаемости кода — до тех пор, пока у вас нет сверхсложных циклов и т. д., Все в порядке.
не похоже, что они были в одной лиге с перейти. 🙂
в вашем примере вы не знаете количество итераций для на петли. Почему бы не использовать во время цикл вместо этого, который позволяет количество итераций быть неопределенным в начале?
поэтому нет необходимости использовать перерыв справка о месячных В общем, как цикл можно лучше сформулировать как во время петли.
-
ресурс, полученный в верхней части блока, может быть выпущен в нижней части (это верно даже для блоков внутри for петли), но этот шаг может быть случайно пропущены при «преждевременный» выход вызван break оператор (в «современном» C++ «RAII» используется для обработки этого надежным и безопасным для исключений способом: в основном, деструкторы объектов освобождают ресурсы надежно независимо от того, как выходит область)
-
кто-то может изменить проверяемое условие в for заявление, не замечая, что есть другие делокализованные условия выхода
-
ответ ndim замечает, что некоторые люди могут избегать break s для поддержания a относительно последовательное время выполнения цикла, но вы сравнивали break против использования булевой переменной управления ранним выходом, где это не удерживает
- у них есть структура разработки, которая поощряет определенный стиль программирования / кода, и у них есть статистические данные о том, что это дает чистую выгоду в этой ограниченной структуре, или
- на них повлияли рекомендации по программированию или опыт работы в таких рамках, или
- они просто диктаторские идиоты, или
- любой из вышеприведенная + историческая инерция (уместная в том, что обоснования более применимы к C, чем современный C++).
это вполне допустимо для использования break — как указывали другие, это нигде в той же лиге, что и goto .
хотя вы можете использовать vFound переменная, когда вы хотите проверить вне цикла, было ли найдено значение в массиве. Также с точки зрения ремонтопригодности может быть полезно иметь общий флаг, сигнализирующий о критериях выхода.
Я не вижу причин, почему это было бы плохой практикой при условии, что вы хотите завершить остановку обработки в этот момент.
во встроенном мире существует много кода, который использует следующую конструкцию:
это очень общий пример, много вещей происходит за занавесом, прерывает в частности. Не используйте это как шаблонный код, я просто пытаюсь проиллюстрировать примером.
мое личное мнение заключается в том, что нет ничего плохого в написании цикла таким образом, пока принимаются соответствующие меры, чтобы предотвратить пребывание в цикле безгранично.
зависит от вашего варианта использования. Существуют приложения, в которых время выполнения цикла for должно быть постоянным (например, для удовлетворения некоторых временных ограничений или для скрытия внутренних данных от атак на основе синхронизации).
в этих случаях будет даже иметь смысл установить флаг и только проверить значение флага после всех for циклические итерации фактически выполняются. Конечно, все итерации цикла for должны запускать код, который по-прежнему занимает примерно одно и то же время.
Если вы не забота о времени выполнения. используйте break; и continue; чтобы облегчить чтение кода.
- 19 были использованы внутри switch операторы (у нас есть только 3 оператора switch в общей сложности!).
- 2 были использованы внутри for loops-код, который я сразу же классифицировал как рефакторинг в отдельные функции и заменил на return заявление.
- как для финал break внутри while петли. Я побежал git blame чтобы увидеть, кто написал эту хрень!
On Мишра 98 правил, которые используются в моей компании в C dev, оператор break не должен использоваться.
Edit: перерыв разрешен в MISRA ‘ 04
Я не согласен!
Почему вы игнорируете встроенную функциональность цикла for, чтобы сделать свой собственный? Вам не нужно изобретать велосипед.
Я думаю, что это имеет больше смысла, чтобы ваши проверки в верхней части вашего цикла for, Как так
или если вам нужно сначала обработать строку
таким образом, вы можете написать функцию, чтобы выполнить все и сделать гораздо более чистый код.
или если ваше состояние сложно вы можете переместить этот код тоже!
«профессиональный код», который пронизан перерывами, на самом деле не звучит как профессиональный код для меня. Это звучит как ленивое кодирование 😉
конечно, break; Это решение для остановки цикла for или цикла foreach. Я использовал его в php в foreach и для цикла и нашел работу.
Почему плохая практика использовать метки break / continue в ООП (например, Java, C#) [закрыто]
Мне сказали, что использование ярлыков break и continue на языке ООП не является стилем программирования ООП. Можете ли вы подробно объяснить, почему и в чем проблема? Фокус был в этом слове. Я имел в виду надпись break/continue.
5 ответов
человек, который сказал вам, что, вероятно, означает, что break и continue являются разветвленными утверждениями, такими как goto, которые являются одним из механизмов императивного программирования.
перерыв / продолжить только позволяют перейти к внешней инструкции, что означает, что вы не можете идти везде в коде. Таким образом, вы остаетесь в том же объекте метода, поэтому он не несовместим с OOP.
в любом случае, говорить, что перерыв и продолжить не ООП-это не смысл. Мы можем обсудить их влияние на читаемость может быть, но это все.
Break и continue не функциональное стиль программирования. В ООП нет ничего, что предполагает break , continue или даже goto внутри метода-плохая идея.
IMHO использование break и continue не рекомендуется в языках ООП, поскольку они могут привести к сложности и путанице. Поскольку ярлыки используются редко, они могут запутать еще больше. Я бы сказал, что вы все равно должны использовать их, когда чувствуете, что это самое простое решение проблема.
еще одно заблуждение использовать
хорошее использование метки
нечетное использование метки
Брюс Экель написал в» мышлении на Java «следующую идею:» важно помнить, что единственная причина использования меток в Java-это когда у вас есть вложенные циклы, и вы хотите сломать или продолжить через более чем один вложенный уровень.»
на самом деле, когда вы не используете lables, рабочий процесс кода во многих случаях более ясен.
совет не использовать break / continue, вероятно, не связан с ООП. Он основан на том, что эти утверждения похожи на печально известный GOTO, который может сделать код полностью нечитаемым. Однако, догмы плохие советы. Основной парадигмой должна быть читаемость кода. Выпрыгивание из цикла в первой строке с помощью break или continue может быть намного яснее, чем помещение всего остального в условие if.
Я думаю, что основная причина в том, что код не так понятен с break и continue.
но также могут быть некоторые проблемы с производительностью (не связанные с ООП): CPU использует предикторы для загрузки инструкции в очередь перед обработкой этой инструкции. Предиктору легко определить, какие инструкции загружать дальше для условного прыжка, и будет сложнее для безусловного.