Иногда мне нужны циклы, которые нуждаются в перерыве:
for(int i=0;i<array.length;i++){
//some other code
if(condition){
break;
}
}
Мне неудобно писать
if(condition){
break;
}
потому что он потребляет 3 строки кода. И я обнаружил, что цикл можно переписать так:
↓
for(int i=0;i<array.length && !condition;i++){
//some other code
}
Поэтому мой вопрос заключается в том, является ли хорошей практикой перемещение условия в поле условия, чтобы уменьшить количество строк кода, если это возможно?
coding-style
loops
ocomfd
источник
источник
condition
конкретно.for(int i=0;i<array.length && !condition;i++)
относительно необычно и может быть упущено кем-то, кто просто просматривает код; это может быть хорошим вариантом использования для циклаwhile
илиdo while
, который чаще всего имеет несколько условий прерывания в определении цикла.Ответы:
Те два примера, которые вы привели, не являются функционально эквивалентными. В оригинале тест условия выполняется после раздела «некоторый другой код», тогда как в модифицированной версии он выполняется первым в начале тела цикла.
Код никогда не должен быть переписан с единственной целью уменьшения количества строк. Очевидно, это хороший бонус, когда он работает таким образом, но это никогда не должно делаться за счет читабельности или правильности.
источник
Я не покупаю аргумент, что «он потребляет 3 строки кода» и, следовательно, это плохо. В конце концов, вы можете написать это так:
и просто потреблять одну строку.
Если он
if
появляется в середине цикла, он, конечно, должен существовать как отдельный тест. Однако, если этот тест появляется в конце блока, вы создали цикл, который имеет тест продолжения на обоих концах цикла, возможно, добавляя сложности к коду. Имейте в виду, что иногдаif (condition)
проверка может иметь смысл только после выполнения блока.Но предположим, что это не так, приняв другой подход:
условия выхода сохраняются вместе, что может упростить вещи (особенно, если « какой-то другой код » длинный).
Там нет правильного ответа здесь, конечно. Так что помните об идиомах языка, о правилах кодирования вашей команды и т. Д. Но в целом, я бы выбрал подход единого теста, когда это имеет функциональный смысл.
источник
Этот вопрос вызвал споры почти столько же времени, сколько программирование. Чтобы бросить свою шляпу в кольцо, я бы выбрал версию с
break
условием и вот почему (для этого конкретного случая):for
Петля просто есть указание перебора значений в цикле. Кодирование нарушающего условия внутри этого просто портит логику ИМО.Наличие отдельного
break
элемента делает кристально ясным, что во время обычной обработки значения являются такими, как указано вfor
цикле, и обработка должна продолжаться, за исключением случаев, когда возникает условие.В качестве предыстории я начал с кодирования a
break
, затем поместил условие вfor
цикл на годы (под руководством исключительного программиста), а затем вернулся кbreak
стилю, потому что он казался намного чище (и был преобладающим стилем в различные кодовые тома, которые я потреблял).Это еще одна из тех священных войн в конце дня - некоторые говорят, что вы никогда не должны вырываться из цикла искусственно, иначе это не настоящий цикл. Делайте все, что чувствуете читаемым (как для себя, так и для других). Если вам действительно нужно уменьшить количество нажатий клавиш, поиграйте в гольф на выходных - пиво по желанию.
источник
for
циклы используются, когда число итераций известно (например, когда нет условия прерывания, кроме конца массива / списка), аwhile
когда нет. Это похоже на случайwhile
цикла. Если проблема заключается в читабельности, тоidx+=1
внутри цикла читать намного чище, чем вif/else
блокеfor(int i=0; i<something;i++)
циклам, что, полагаю, половина разработчиков на самом деле не помнят, чтоfor
циклы можно использовать по-разному, и, следовательно, им сложно разобраться в&&condition
части.for(;;)
...for
Циклы предназначены для итерации по чему-то 1 - они не просто заголовки, которые можно найти в заголовке - три выражения имеют очень конкретные значения:Идея состоит в том, чтобы отделить обработку итераций ( как выполнять итерацию) от логики внутри цикла ( что делать в каждой итерации). Во многих языках обычно есть цикл for-each, который освобождает вас от деталей итерации, но даже если ваш язык не имеет такой конструкции или если ее нельзя использовать в вашем сценарии - вы все равно должны ограничить заголовок цикла к итерационной обработке.
Итак, вы должны спросить себя - ваше условие об обработке итерации или о логике внутри цикла? Скорее всего, речь идет о логике внутри цикла, поэтому ее следует проверять внутри цикла, а не в заголовке.
1 В отличие от других циклов, которые «ждут», чтобы что-то произошло. Цикл
for
/foreach
должен иметь концепцию «списка» элементов для итерации, даже если этот список ленивый, бесконечный или абстрактный.источник
someFunction(array[i])
. Теперь обе части условия относятся к тому, что вы итерируете, и имеет смысл объединить их с&&
заголовком цикла.for
в основе цикла лежат счетчики, а не циклы над списком, и это поддерживается синтаксисомfor
более ранних языков (эти языки часто имелиfor i = 1 to 10 step 2
синтаксис, аstep
команда - даже допускала начальное значение, которое не является индексом первого элемент - указывает на числовой контекст, а не на контекст списка). Только случай использования , что я думаю , что опорыfor
петли , как только итерация список является parallelising, и это требует явного синтаксиса сейчас в любом случае для того , чтобы не нарушать код делает, к примеру, своего рода.Я рекомендую использовать версию с
if (condition)
. Это более читабельно и легче для отладки. Написание 3 дополнительных строк кода не сломает ваши пальцы, но поможет следующему человеку понять ваш код.источник
naming things
должным образом, чтобы понять, что происходит и когда выполняется условие нарушения.Если вы перебираете коллекцию, в которой некоторые элементы должны быть пропущены, я рекомендую новую опцию:
И Java, и C # делают это относительно тривиально. Я не удивлюсь, если бы в C ++ был способ создать причудливый итератор, чтобы пропустить некоторые неприменимые элементы. Но на самом деле это вариант, только если ваш язык поддерживает его, и причина, по которой вы используете его,
break
заключается в том, что существуют условия того, обрабатываете ли вы элемент или нет.В противном случае есть очень веская причина сделать ваше условие частью цикла for - при условии, что его первоначальная оценка верна.
Я работал над кодом, где ваш цикл for занимает несколько сотен строк с несколькими условными выражениями и сложной математической схемой. Проблемы, с которыми вы сталкиваетесь при этом:
break
команды, похороненные в логике, трудно найти, а иногда и удивляютВ этой ситуации я рекомендую следующие рекомендации в порядке предпочтения:
break
если это возможноbreak
в верхней части цикла, если это возможноЭти рекомендации всегда зависят от правильности вашего кода. Выберите вариант, который наилучшим образом отражает намерения и улучшит ясность вашего кода.
источник
continue
утверждениях, но я не понимаю, как они сильно помогаютbreak
.takeWhile
Фильтр может заменитьbreak
операторы. Если у вас есть один - Java, например , только получает их в Jave 9 (не то, что это , что трудно реализовать его самостоятельно)Я настоятельно рекомендую придерживаться подхода наименьшего удивления, если вы не получите значительную выгоду, поступая иначе.
Люди не читают каждую букву при чтении слова, и они не читают каждое слово при чтении книги - если они умеют читать, они смотрят на контуры слов и предложений и позволяют своему мозгу заполнить остальные ,
Так что, скорее всего, случайный разработчик предположит, что это просто стандарт для цикла и даже не смотрит на него:
Если вы хотите использовать этот стиль независимо, я рекомендую изменить части,
for(int i=0;i<
и;i++)
это скажет читателю, что это стандарт для цикла.Еще одна причина, по которой стоит пойти
if
-break
это то, что вы не всегда можете использовать свой подход сfor
условием. Вы должны использоватьif
-break
когда условие прерывания слишком сложное, чтобы его можно было скрыть внутриfor
оператора, или полагается на переменные, которые доступны только внутриfor
цикла.Так что, если вы решите пойти с
if
-break
, вы прикрыты. Но если вы решили использоватьfor
-условия, вы должны использовать сочетаниеif
-break
иfor
-условий. Чтобы быть последовательным, вам придется перемещать условия назад и вперед междуfor
-условиями иif
-break
всякий раз, когда условия меняются.источник
Ваше преобразование предполагает, что все, что
condition
оценивается,true
при входе в цикл. Мы не можем комментировать правильность этого в этом случае, потому что это не определено.Добившись успеха в «сокращении строк кода» здесь, вы можете перейти к
и применить то же преобразование, достигнув
Что является недопустимым преобразованием, как вы сейчас безоговорочно делаете,
further code
где раньше не делали.Гораздо более безопасная схема преобразования заключается в извлечении
some other code
и оценкеcondition
отдельной функции.источник
TL; DR. Делай то, что лучше всего в твоих конкретных обстоятельствах.
Давайте возьмем этот пример:
В этом случае мы не хотим, чтобы какой-либо код в цикле for выполнялся, если он
something
равен true, поэтому перенос тестаsomething
в поле условия является разумным.Опять же, в зависимости от того,
something
можно ли установить значениеtrue
перед циклом, но не внутри него, это может дать больше ясности:Теперь представьте это:
Мы посылаем очень четкое сообщение там. Если
something
во время обработки массива становится истинным, то на этом этапе откажитесь от всей операции. Чтобы переместить чек в поле условия, необходимо сделать:Возможно, «сообщение» стало мутным, и мы проверяем состояние отказа в двух местах - что, если состояние отказа меняется, и мы забываем одно из этих мест?
Есть, конечно, много разных форм, которые могут быть для цикла и условия, все со своими нюансами.
Напишите код так, чтобы он читался хорошо (это, очевидно, несколько субъективно) и кратко. За пределами драконовского набора правил кодирования все «правила» имеют исключения. Напишите, что, по вашему мнению, лучше всего отражает принятие решения, и сведите к минимуму вероятность ошибок в будущем.
источник
Хотя это может быть привлекательным, потому что вы видите все условия в заголовке цикла и
break
можете сбивать с толку внутри больших блоков,for
цикл - это шаблон, в котором большинство программистов ожидают циклы в некотором диапазоне.Тем более что добавление дополнительного условия прерывания может привести к путанице, и будет сложнее увидеть, является ли оно функционально эквивалентным.
Часто хорошей альтернативой является использование цикла
while
или,do {} while
который проверяет оба условия, предполагая, что в вашем массиве есть хотя бы один элемент.Используя цикл, который только проверяет условие, а не запускает код из заголовка цикла, вы очень четко даете понять, когда проверяется условие и что является фактическим условием и что такое код с побочными эффектами.
источник
for(...; i <= n; ...)
) на самом деле делает код труднее читать , потому что у меня есть остановиться и подумать о том, что здесь происходит, и может вообще пропустить условие на первом проходе, потому что я не ожидаю, что оно будет там. Для меняfor
цикл подразумевает, что вы зацикливаетесь на некотором диапазоне, если есть специальное условие выхода, его следует сделать явным с помощьюif
или, или вы можете использоватьwhile
.Это плохо, так как код предназначен для чтения людьми - неидиоматические
for
циклы часто сбивают с толку, что означает, что ошибки, скорее всего, скрываются здесь, но исходный код, возможно, можно было улучшить, сохранив его и то и другое. коротко и читабельно.Если вам нужно найти значение в массиве (предоставленный пример кода несколько универсален, но это может быть и такой шаблон), вы можете просто явно попытаться использовать функцию, предоставляемую языком программирования специально для этой цели. Например (псевдокод, поскольку язык программирования не был указан, решения варьируются в зависимости от конкретного языка).
Это должно заметно сократить время решения и упростить его, поскольку ваш код говорит именно то, что вам нужно.
источник
Несколько причин, по моему мнению, говорит, что вы не должны.
do...while
цикла (неwhile
), поскольку условие проверяется после выполнения некоторого кода.Но вдобавок ко всему, рассмотрим это,
Теперь, вы действительно можете достичь этого, добавив эти условия в это
for
условие?источник
Я думаю, что удаление
break
может быть хорошей идеей, но не для сохранения строк кода.Преимущество написания без него
break
состоит в том, что пост-условие цикла является очевидным и явным. Когда вы закончите цикл и выполните следующую строку программы, ваше условие циклаi < array.length && !condition
должно быть ложным. Следовательно, либоi
был больше или равен длине вашего массива, либоcondition
имеет значение true.В версии с
break
есть скрытая ошибка. Условие цикла говорит о том, что цикл завершается, когда вы запускаете какой-то другой код для каждого действительного индекса массива, но на самом деле существуетbreak
оператор, который может завершить цикл до этого, и вы не увидите его, пока не просмотрите код цикла очень осторожно. А у автоматических статических анализаторов, в том числе оптимизирующих компиляторов, могут возникнуть проблемы с определением того, каковы пост-условия цикла.Это было первоначальной причиной, по которой Эдгар Дейкстра написал «Goto считает опасным». Это не было вопросом стиля: нарушение цикла затрудняет формальное рассуждение о состоянии программы. Я написал множество
break;
утверждений в своей жизни, и однажды, будучи взрослым, я даже написалgoto
(чтобы разорвать несколько уровней критичного к производительности внутреннего цикла и затем перейти к другой ветви дерева поиска). Тем не менее, у меня гораздо больше шансов написать условныйreturn
оператор из цикла (который никогда не запускает код после цикла и, следовательно, не может испортить его постусловия), чем abreak
.постскриптум
На самом деле, для рефакторинга кода с тем же поведением может потребоваться больше строк кода. Ваш рефакторинг может быть действительным для какого-то другого кода или если мы сможем доказать, что он
condition
будет начинаться с false. Но ваш пример в общем случае эквивалентен:Если какой-то другой код не является однострочным, вы можете затем переместить его в функцию, чтобы не повторять себя, и тогда вы почти реорганизовали свой цикл в хвостовую рекурсивную функцию.
Я признаю, что это был не основной вопрос вашего вопроса, и вы держали его в простоте.
источник
break
заявления, то вы знаете, что такое условие цикла и что цикл останавливается, когда это условие ложно. Если естьbreak
? Тогда есть несколько способов, которыми цикл может завершиться, и в общем случае выяснение, когда один из них может остановить цикл, буквально решает проблему остановки. На практике меня больше беспокоит то, что цикл выглядит так, как будто он делает одно, но на самом деле тот, кто написал код после цикла, пропустил крайний случай, скрытый в его сложной логике. Вещество в петле трудно пропустить.Да, но ваш синтаксис нетрадиционен и, следовательно, плох (тм)
Надеюсь, ваш язык поддерживает что-то вроде
источник
while
подчеркивает монстра в коде - исключение, скрытое в обычном / обычном коде. Бизнес-логика находится впереди и в центре, механика циклов включена. Это позволяет избежать реакции «подожди минуту ...» наfor
альтернативу цикла. Этот ответ решает проблему. абсолютно голосование.Если вы обеспокоены тем, что слишком сложное
for
утверждение трудно прочитать, это определенно является серьезной проблемой. Потеря вертикального пространства также является проблемой (хотя и менее критичной).(Лично мне не нравится правило, что
if
операторы должны всегда иметь фигурные скобки, что в значительной степени является причиной потери вертикального пространства здесь. Обратите внимание, что проблема заключается в потере вертикального пространства. Использование вертикального пространства со значимыми линиями не должно быть проблемой.)Один из вариантов - разделить его на несколько строк. Это определенно то, что вам следует делать, если вы используете действительно сложные
for
операторы с несколькими переменными и условиями. (Это лучше для меня использовать вертикальное пространство, давая как можно больше строк чего-то значимого.)Лучшим подходом может быть попытка использовать более декларативную и менее императивную форму. Это будет зависеть от языка, или вам может потребоваться написать свои собственные функции, чтобы включить такого рода вещи. Это также зависит от того, что на
condition
самом деле. Предположительно он должен быть в состоянии изменить как-то, в зависимости от того, что находится в массиве.источник
for
утверждение на несколько строк - лучшая идея во всей этой дискуссииОдна вещь, которая была забыта: когда я вырываюсь из цикла (не делаю все возможные итерации, независимо от того, как он реализован), обычно бывает так, что я не только хочу выйти из цикла, я также хочу знать, почему это произошло , Например, если я ищу элемент X, я не только вырываюсь из цикла, я также хочу знать, что X был найден и где он находится.
В этой ситуации наличие условия вне цикла вполне естественно. Итак, я начинаю с
и в цикле я напишу
с петлей для
Теперь проверка условия в цикле вполне закономерна. Наличие оператора "break" зависит от того, есть ли дальнейшая обработка в цикле, которую вы хотите избежать. Если какая-то обработка необходима, а другая нет, у вас может быть что-то вроде
где-то в вашей петле.
источник