for 루프 내에서 가능한 경우 중단 조건을 조건 필드로 이동해야합니까? [닫은]


48

때로는 다음과 같은 휴식이 필요한 루프가 필요합니다.

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
}

그래서 내 질문은 가능하면 조건을 조건 필드로 이동하여 코드 줄을 줄이는 것이 좋습니다.


7
condition특히 무엇인지에 달려 있습니다 .
Bergi

4
misra가 루프 내에서 "break"및 "continue"의 사용을 금지하는 이유가 있습니다. 참조 : stackoverflow.com/q/3922599/476681
BЈовић

35
줄 수 자체는 실제 문제가 아니라고 생각합니다. 한 줄에 쓸 수 있습니다. if (조건) 중단; 내 생각에 문제는 가독성입니다. 루프 조건을 사용하는 것보다 루프를 깨는 것을 개인적으로 싫어합니다.
Joe

97
3 줄의 코드 A를 사용하기 때문에 어떤 스타일을 싫어하는 아주, 매우 나쁜 이유입니다. IMO "코드 라인 소비"는 관련이없는 것과 좋은 것 사이에 있습니다. 너무 적은 행에 너무 많은 로직을 넣으려고하면 읽을 수없는 코드와 찾기 어려운 버그가 발생합니다.
Andrew Henle

3
아마도 인기가없는 의견 : for(int i=0;i<array.length && !condition;i++)비교적 드물고 코드를 감추고있는 누군가가 간과 할 수도 있습니다. 이는 루프 정의에 여러 중단 조건이 있는 whileor do while루프에 대한 유스 케이스 일 수 있습니다 .
Jules

답변:


155

귀하가 제공 한 두 가지 예는 기능적으로 동일하지 않습니다. 원래 조건 테스트는 "일부 다른 코드"섹션 이후에 수행되는 반면 수정 된 버전에서는 루프 본문의 시작 부분에서 먼저 수행됩니다.

줄 수를 줄이려는 목적으로 만 코드를 다시 작성해서는 안됩니다. 분명히 그렇게하면 좋은 보너스이지만 가독성이나 정확성을 희생해서는 안됩니다.


5
나는 당신의 감정을 이해하지만 루프가 수백 줄 길이이고 여러 조건부 중단이있는 레거시 코드를 충분히 유지했습니다. 코드가 예상 한 조건부 중단에 도달 할 것으로 예상 할 때 디버깅이 매우 어려워 지지만 이전 코드에서는 먼저 조건부 중단이 발생했습니다. 그 코드를 어떻게 처리합니까? 위와 같은 짧은 예에서는 너무 일반적인 시나리오를 잊어 버리기 쉽습니다.
Berin Loritsch

84
@BerinLoritsch :이를 처리하는 올바른 방법은 수백 줄 길이의 루프가없는 것입니다!
Chris

27
@ Walfrat : 다시 작성하는 것이 옵션이 아니라면 더 이상 의문의 여지가 없습니다. 일반적으로 "추출 방법"유형 리 팩터를 사용하여 코드 블록을 이동하면 기본 메소드 루프가 짧아지고 논리 흐름이 더 분명해지기를 바랍니다. 실제로는 상황에 따라 다릅니다. 나는 메소드를 짧게 유지하고 다음 루프 로직을 짧게 유지하는 일반적인 규칙을지지하지만 일반적인 의미에서 그 이상의 것을 말하고 싶지는 않지만 ...
Chris

4
@AndrewHenle의 간결함은 가독성입니다. 최소한 세부 정보가 증가 하면 항상 가독성과 유지 관리 성이 줄어든다 는 의미입니다 . LOC를 줄이는 것은 밀도를 높이고 추상화 수준을 높여서 달성되며이 사이트의 다른 Q / A 쌍에서 입증 된 바와 같이 유지 관리 성과 밀접하게 관련되어 있습니다.
Leushenko

5
@Joe a Do-While 구문은 매우 드물기 때문에 나중에 해당 코드를 유지해야하는 개발자를 트립하기 쉽습니다. 몇몇 개발자들은 실제로 그들을 보지 못했습니다! 어떤 경우, 그것은 것 - 할 - 동안 전혀 가독성을 향상시킬 것입니다 있는지 확실하지 않습니다 증가 코드를 이해하기 어려움. 예를 들어, 현재 코드베이스는 15 세 정도이며 LOC는 2 백만 정도입니다. 약 50 명의 개발자가 이미 그것을 만졌습니다. 정확히 제로 do-while 루프가 있습니다!
T. Sar-복권 모니카

51

나는 "3 줄의 코드를 소비한다"라는 주장을 사지 않는다. 결국, 다음과 같이 쓸 수 있습니다.

if (condition) break;

한 줄만 소비하면됩니다.

if루프 중간 에 나타나는 경우에는 별도의 테스트로 존재해야합니다. 그러나이 테스트가 블록의 끝에 나타나면 루프의 양쪽 끝에 계속 테스트를 수행하여 코드의 복잡성을 증가시키는 루프를 생성 한 것입니다. 그러나 때때로 if (condition)테스트는 블록이 실행 된 후에 만 ​​의미가있을 수 있습니다.

그러나 다른 접근법을 채택하여 그렇지 않다고 가정하면 다음과 같습니다.

for(int i=0;i<array.length && !condition;i++){
    //some other code
}

종료 조건이 함께 유지되므로 상황을 단순화 할 수 있습니다 (특히 " 다른 코드 "가 긴 경우).

물론 여기에는 정답이 없습니다. 따라서 언어의 관용구, 팀의 코딩 규칙 등을 알고 있어야합니다. 그러나 균형을 유지하기 위해 기능적으로 의미가있는 경우 단일 테스트 방식을 채택합니다.


14
@ jpmc26, 더 좋습니까? 아니요. 유효한 대안 스타일입니까? 물론이야.
David Arno

6
나중에 코드를 편집 할 때 엉망이되고 눈에 띄는 단점이없는 것이 좋습니다.
jpmc26

4
"루프 내용이 길 수 있습니다"때문에 함께 유지하는 것은 약한 논쟁으로 보입니다. 콘텐츠를 읽기가 어려운 경우 두 줄의 코드를 저장하는 것 외에 다른 문제가 있습니다.
BlueWizard

12
@ jpmc26 동의하지 않습니다. 이 답변에 따라 가장 짧은, 한 개의 라이너 조건에서 괄호는 불필요한 혼란입니다. 그렇지 않으면 눈에 더 우아하고 쉽습니다. 그것들은 삼항 조건 연산자와 같습니다. 나는 큰 괄호를 더 큰 문장 블록으로 나누면서 중괄호를 추가하는 것을 결코 잊지 않았다. 나는 이미 개행을 추가하고 있습니다.
benxyzzy

3
그것은 모두 스타일 선호 사항이지만, 그것이 더 안전하다는 주장을한다면, 나는 그 추론에 동의하지 않을 것입니다. 나 자신은 중괄호없이 다음 줄에 선호하지만, 그게 더 또는 덜 유효한 다른 스타일에 비해입니다 의미하지 않는다
phflack

49

이런 종류의 질문은 프로그래밍이 진행되는 한 거의 논쟁을 불러 일으켰습니다. 모자를 반지에 던지기 위해 break조건이 있는 버전으로 갈 것 입니다.이 특별한 이유는 다음과 같습니다 .

for루프는 루프에서 반복하는 값을 지정하는 단지가있다. 그 안의 파괴 조건을 코딩하면 논리 IMO가 혼란스러워집니다.

별도의 break처리를하면 정상 처리 중에 값이 for루프에 지정된대로되며 조건이 발생한 곳을 제외 하고 처리가 계속되어야합니다 .

약간의 배경으로, 나는 코딩을 시작한 break다음 for몇 년 동안 (예비 한 프로그래머의 지시에 따라) 루프에 조건을 넣은 다음 break훨씬 더 깨끗하다고 ​​느끼기 때문에 스타일 로 돌아갔습니다 (그리고 일반적인 스타일이었습니다. 내가 소비 한 다양한 코드 테마).

그것은 하루의 끝에 그 거룩한 전쟁의 또 다른입니다 - 일부는 당신이해야한다고 결코 인위적으로 루프의 탈옥하지, 그렇지 않으면 진짜 루프가 아닙니다. 읽을 수 있다고 생각되는 모든 것을하십시오 (자신과 다른 사람들 모두를 위해). 키 입력을 줄이는 것이 실제로 당신의 일이라면 주말에 코드 골프를 타십시오-맥주 옵션.


3
조건이 "found"와 같이 이름이 좋은 경우 (예를 들어, 배열을 통해 무언가를 찾고있는 경우) for 루프의 헤드에 배치하는 것이 좋습니다.
user949300

1
for반복 횟수가 알려진 경우 (예 : 중단 조건이 없지만 배열 / 목록의 끝) 및 while그렇지 않은 경우 루프가 사용 된다고 들었습니다 . 이것은 while루프 의 경우 인 것 같습니다 . 가독성이 문제라면 idx+=1루프 내부를 if/else블록 보다 읽기가 더 깨끗합니다.
Laiv

다음에 코드가 있으면 루프에 중단 조건을 넣을 수 없으므로 최소한 "if (condition) {found = true; 계속;}
gnasher729

우리는 for(int i=0; i<something;i++)루프에 너무 익숙 하여 개발자의 절반이 for루프를 다르게 사용할 수 있다는 것을 기억하지 못 하기 때문에 &&condition부분을 이해하기가 어렵습니다 .
Ralf Kleberhoff

@RalfKleberhoff 실제로. tripart 문 표현이 모두 선택 사항이라는 많은 새로운 개발자 표현 놀라움을 보았습니다. 내가 본 마지막 순간도 기억 나지 않습니다 for(;;)...
Robbie Dee

43

for루프는 무언가 1에 대한 반복 위한 것입니다 -그것들은 단지 lol-let's-pull-some-random-stuffs-the-body-and-put-them-in-the-loop-header가 아닙니다. 구체적인 의미 :

  • 첫 번째는 이터레이터 를 초기화하는 것 입니다. 인덱스, 포인터, 반복 객체 또는 반복에 사용되는 모든 것이 될 수 있습니다 .
  • 두 번째는 우리가 끝에 도달했는지 확인하는 것입니다.
  • 세 번째는 이터레이터를 진행시키는 것입니다.

아이디어는 (처리 반복 분리하는 방법 루프 (내부의 논리에서 반복하기를) 무엇을 각 반복에서 할). 많은 언어에는 일반적으로 반복의 세부 사항을 완화하는 for-each 루프가 있지만 언어에 해당 구문이 없거나 시나리오에서 사용할 수없는 경우에도 여전히 루프 헤더를 제한해야합니다 반복 처리.

따라서 반복 처리 또는 루프 내부의 논리에 대한 조건입니까? 가능성은 루프 내부의 논리에 관한 것이므로 헤더가 아닌 루프 내부에서 확인해야합니다.

1 다른 루프와 달리, 어떤 일이 일어나기를 기다리고 있습니다. for/ foreach루프에서 반복 할 항목의 "목록"의 개념을 가져야한다 - 그 목록은 게으른 또는 무한 또는 추상 경우에도.


5
이것이 제가 질문을 읽을 때 처음으로 생각한 것입니다. 실망했다 나는 누군가가 그것을 말하는 것을보기 위해 6 개의 답변을 스크롤해야했다
Nemo

4
음 ... 모든 루프는 반복을위한 것입니다. "iteration"이라는 단어의 의미는 :-)입니다. "컬렉션 반복하기"또는 "반복자를 사용하여 반복하기"와 같은 것을 의미한다고 가정하십니까?
psmears

3
@psmears 좋아요, 아마도 잘못된 단어를 선택했을 것입니다. 영어는 모국어가 아니며 반복을 생각할 때 "무엇보다 반복"을 생각합니다. 나는 대답을 고칠 것이다.
Idan Arye

중간 사례는 조건이 다음과 같은 경우 someFunction(array[i])입니다. 이제 조건의 두 부분이 반복하는 것에 관한 것이므로 &&루프 헤더에서 이들을 결합하는 것이 좋습니다.
Barmar

나는 당신의 입장을 존중하지만 동의하지 않습니다. 나는 for마음 for속의 루프가 목록의 루프가 아니라 카운터 라고 생각 합니다. 이것은 이전 언어 의 구문에서 지원 됩니다 (이러한 언어는 종종 for i = 1 to 10 step 2구문 이 있었고 step명령은 처음의 색인이 아닌 초기 값을 허용합니다) 요소-목록 컨텍스트가 아닌 숫자 컨텍스트에서 힌트). 단지 내가 지원을 생각하는 사용 사례 for로만 병렬화 된 목록을 반복 루프, 그리고 예를 들어,하고 암호를 해독하지하기 위해 지금 어쨌든 종류의 명시 적 구문을 필요로한다.
Logan Pickup

8

와 함께 버전을 사용하는 것이 좋습니다 if (condition). 더 읽기 쉽고 디버깅하기 쉽습니다. 3 줄의 코드를 추가로 작성해도 문제가 해결되지는 않지만 다음 사람이 쉽게 코드를 이해할 수 있습니다.


1
루프 블록에 수백 줄의 코드가없고 그 안에있는 논리는 로켓 과학이 아닙니다. 나는 당신의 주장은 괜찮다고 생각하지만, naming things무슨 일이 일어나고 있는지, 깨는 조건을 충족시키는지를 이해하기 위해 적절하게 그리워합니다 .
Laiv

2
@Laiv 루프 블록에 수백 줄의 코드가 있으면 중단 조건을 작성하는 위치보다 문제가 더 큽니다.
Aleksander

그렇기 때문에 나는 항상 사실이 아니기 때문에 정황에 맞는 답을 제안했습니다.
Laiv

8

특정 요소를 건너 뛰어야하는 컬렉션을 반복하는 경우 새로운 옵션을 권장합니다.

  • 반복하기 전에 컬렉션을 필터링하십시오.

Java와 C # 모두이 작업을 비교적 간단하게 만듭니다. C ++에 적용되지 않는 특정 요소를 건너 뛰기 위해 멋진 반복자를 만드는 방법이 있다면 놀라지 않을 것입니다. 그러나 이것은 선택한 언어가 지원하는 경우에만 실제로 선택 사항이며, 사용하는 이유 break는 요소를 처리할지 여부에 대한 조건이 있기 때문입니다.

그렇지 않으면 조건이 for 루프의 일부가되어야하는 아주 좋은 이유가 있습니다. 초기 평가가 정확하다고 가정합니다.

  • 루프가 일찍 끝나는 시점을 쉽게 알 수 있습니다.

나는 for 루프가 몇 개의 조건부와 복잡한 수학이있는 수백 줄을 취하는 코드를 연구했습니다. 이 문제로 인해 발생하는 문제는 다음과 같습니다.

  • break 논리에 묻힌 명령은 찾기 어렵고 때로는 놀랍습니다.
  • 디버깅은 진행 상황을 진정으로 이해하기 위해 루프의 각 반복을 단계별로 수행해야합니다.
  • 많은 코드에는 쉽게 뒤집을 수있는 리팩토링이나 단위 테스트가 없으므로 재 작성 후 기능적 동등성을 지원합니다.

그러한 상황에서는 다음 지침을 선호 순서대로 권장 합니다.

  • break가능한 경우 수집을 필터링하여
  • for 루프 조건의 조건부로 만들기
  • break가능하면 루프의 맨 위에 조건을 배치하십시오 .
  • 나누기에주의를 기울이는 여러 줄 주석 추가 및 그 이유

이 지침은 항상 코드 의 정확성 을 따릅니다 . 의도를 가장 잘 나타내고 코드의 선명도를 향상시킬 수있는 옵션을 선택하십시오.


1
이 답변의 대부분은 괜찮습니다. 그러나 ... 컬렉션을 필터링하면 continue문 이 필요 하지 않은 방법을 알 수 있지만 이들이 어떻게 도움이되는지는 알 수 없습니다 break.
user949300

1
@ user949300 takeWhile필터는 break명령문 을 대체 할 수 있습니다 . 예를 들어 Java가있는 경우-예를 들어 Jave 9에서만 가져 옵니다 (직접 구현하기 어렵지는 않습니다 )
Idan Arye

1
그러나 Java에서는 반복 전에 필터링 할 수 있습니다. 스트림 (1.8 이상) 또는 Apache Collections (1.7 이하) 사용
Laiv

@IdanArye-Java 스트림 API에 이러한 기능을 추가하는 추가 라이브러리가 있습니다 (예 : JOO-lambda )
Jules

@IdanArye는 귀하의 의견에 앞서 테이크를 들어 본 적이 없습니다. 필터를 순서에 명시 적으로 연결하면 "정상"필터에서 모든 요소가 이전 또는 이후에 오는 것과 상관없이 true 또는 false를 반환하기 때문에 비정상적이고 해킹 적입니다. 이런 식으로 작업을 병렬로 실행할 수 있습니다.
user949300

8

다른 방법으로 큰 혜택을 얻지 않는 한 최소한의 놀라움으로 접근하는 것이 좋습니다 .

사람들은 단어를 읽을 때 모든 글자를 읽지 않으며 책을 읽을 때 모든 단어를 읽지 않습니다. 읽기에 능숙하다면 단어와 문장의 개요를보고 뇌가 나머지 부분을 채우게합니다. .

따라서 가끔 개발자는 이것이 루프의 표준이고 그것을 보지도 않을 것이라고 가정 할 것입니다.

for(int i=0;i<array.length&&!condition;i++)

에 관계없이 해당 스타일을 사용하려면, 나는 부분을 변경하는 것을 권장 for(int i=0;i<하고 ;i++)이 루프의 표준이라고 그 독자의 두뇌를 말한다.


함께가는 또 다른 이유는 if- break당신은 항상 당신의 방법을 사용할 수 없다는 것입니다 for-condition. 당신은 사용해야합니다 if- break휴식 조건이 내 숨길 너무 복잡 때 for문 또는 내부에서만 액세스 변수에 의존 for루프.

for(int i=0;i<array.length&&!((someWidth.X==17 && y < someWidth.x/2) || (y == someWidth.x/2 && someWidth.x == 18);i++)

따라서 if- 로 가기로 결정 break하면 커버됩니다. 당신이 이동하기로 결정한다면 for-conditions, 당신은 혼합 사용할 필요가 if- breakfor-conditions을. 일관성을 위해, 당신은 앞뒤로 조건을 이동해야합니다 사이 for(가) -conditions와 if- break때마다 조건을 변경합니다.


4

변환은 루프에 들어갈 때 condition평가 되는 것이 무엇이든 가정합니다 true. 정의되지 않았기 때문에이 경우의 정확성에 대해서는 언급 할 수 없습니다.

여기서 "코드 줄 줄이기"에 성공하면 계속해서 살펴볼 수 있습니다.

for(int i=0;i<array.length;i++){
    // some other code
    if(condition){
        break;
    }
    // further code
}

같은 변형을 적용하여

for(int i=0;i<array.length && !condition;i++){
    // some other code
    // further code
}

further code이전에하지 않은 곳에서 무조건 수행 할 수있는 잘못된 변환 입니다.

훨씬 안전한 변환 체계는 별도의 함수 를 추출 some other code하고 평가 condition하는 것입니다.

bool evaluate_condition(int i) // This is an horrible name, but I have no context to improve it
{
     // some other code
     return condition;
}

for(int i=0;i<array.length && !evaluate_condition(i);i++){
    // further code
}

4

TL; DR 특정 상황에서 가장 잘 읽는 것은 무엇이든하십시오

이 예제를 보자 :

for ( int i = 1; i < array.length; i++ ) 
{
    if(something) break;
    // perform operations
}

이 경우 우리는 for 루프의 코드 something가 true 인 경우 실행되는 것을 원하지 않으므로 테스트를 something조건 필드로 옮기는 것이 합리적입니다.

for ( int i = 1; i < array.length && !something; i++ )

그런 다음 루프 이전 something으로 설정할 수 있는지 여부에 따라 다시 true명확하게 제공 할 수 있습니다.

if(!something)
{
    for ( int i = 1; i < array.length; i++ )
    {...}
}

이제 이것을 상상해보십시오.

for ( int i = 1; i < array.length; i++ ) 
{
    // perform operations
    if(something) break;
    // perform more operations
}

우리는 거기에 매우 명확한 메시지를 보내고 있습니다. 경우 something배열을 처리하는 동안 참이 후,이 시점에서 전체 동작을 포기. 검사를 조건 필드로 옮기려면 다음을 수행해야합니다.

for ( int i = 1; i < array.length && !something; i++ ) 
{
    // perform operations
    if(!something)
    {
        // perform more operations
    }
}

아마도 "메시지"가 혼란스러워졌고, 두 곳에서 고장 상태를 점검하고 있습니다. 만약 고장 상태가 바뀌고 그 장소 중 하나를 잊어 버리면 어떨까요?

물론 for 루프와 조건은 모두 고유 한 뉘앙스가있는 더 많은 다른 모양이 있습니다.

코드가 잘 읽히도록 (이것은 다소 주관적 임) 간결하게 코드를 작성하십시오. 드라코 니안 코딩 가이드 라인 외에는 모든 "규칙"에 예외가 있습니다. 자신이 느끼는 것을 의사 결정에 가장 잘 표현하고 미래의 실수 가능성을 최소화하십시오.


2

루프 헤더에 모든 조건이 표시 break되어 큰 블록 안에서 혼동 될 수 있기 때문에 매력적일 수 있지만 , for루프는 대부분의 프로그래머가 일정 범위에서 루프를 기대하는 패턴입니다.

특히 그렇게하기 때문에 추가 중단 조건을 추가하면 혼동을 일으킬 수 있으며 기능상 동등한 지 확인하기더 어렵습니다 .

배열에 요소가 하나 이상 있다고 가정하면 두 조건을 모두 확인 하는 whileor do {} while루프 를 사용하는 것이 좋습니다 .

int i=0
do {
    // some other code
    i++; 
} while(i < array.length && condition);

조건 만 확인하고 루프 헤더에서 코드를 실행하지 않는 루프를 사용하면 조건을 확인할 때와 실제 조건 및 부작용이있는 코드가 무엇인지 명확하게 알 수 있습니다.


이 질문에 이미 좋은 답변이 있음에도 불구하고 중요한 점을 지적했기 때문에 이것을 구체적으로 찬성하고 싶었습니다. for-loop ( for(...; i <= n; ...)) 에 간단한 바운드 검사 이외의 다른 것이 있으면 실제로 코드 를 읽기가 어렵 습니다. 여기서 일어나고있는 일을 멈추고 생각하고 첫 패스에서 조건을 놓칠 수 있습니다. 나에게 for루프는 특정 범위를 반복하고 있음을 의미합니다. 특별한 종료 조건이 있으면를 명시 적으로 지정하거나을 if사용할 수 있습니다 while.
CompuChip

1

코드는 사람이 읽을 수 있기 때문에 좋지 않습니다. 비 아이디 오 매틱 for루프는 종종 읽기가 헷갈 리기 때문에 버그가 여기에 숨어있을 가능성이 높지만 원래 코드를 유지하면서 개선 할 수 있습니다. 짧고 읽을 수 있습니다.

배열에서 값을 찾는 것이라면 (제공된 코드 샘플은 다소 일반적이지만이 패턴 일 수도 있습니다), 프로그래밍 언어에서 제공하는 함수를 해당 목적에 맞게 명시 적으로 사용하면됩니다. 예를 들어 (프로그래밍 언어가 지정되지 않은 의사 코드는 솔루션이 특정 언어에 따라 다릅니다).

array.find(item -> item.valid)

코드가 구체적으로 필요한 것을 말하면 솔루션을 단순화하는 동시에 눈에 띄게 단축됩니다.


1

내 의견으로는 몇 가지 이유가 있습니다.

  1. 가독성이 떨어집니다.
  2. 출력이 같지 않을 수 있습니다. 그러나 일부 코드 실행 후 조건이 확인되므로 do...while루프 (not while)로 수행 할 수 있습니다 .

하지만 그 위에 이것을 고려하십시오.

for(int i=0;i<array.length;i++){

    // Some other code
    if(condition1){
        break;
    }

    // Some more code
    if(condition1){
        break;
    }

    // Some even more code
}

이제 이러한 조건을 해당 for조건 에 추가하여 실제로 달성 할 수 있습니까?


" 개방 " 이란 무엇입니까 ? " 의견 " 을 의미 합니까?
피터 Mortensen

"개방의 몇 가지 이유, 그렇지 않다"는 것은 무엇을 의미 합니까? 정교하게 할 수 있습니까?
Peter Mortensen

0

나는 제거 break하는 것이 좋은 생각 일 수 있지만 코드 줄을 저장하지는 않는다고 생각합니다.

없이 작성 break하면 루프의 사후 조건이 분명하고 명백 하다는 장점이 있습니다. 루프를 끝내고 프로그램의 다음 라인을 실행할 때 루프 조건 i < array.length && !condition이 거짓이어야합니다. 따라서 i배열 길이보다 크거나 같습니다 condition.

의 버전 break에는 숨겨진 문제가 있습니다. 루프 조건에 따르면 각 유효한 배열 인덱스에 대해 다른 코드 를 실행하면 루프가 종료 되지만 실제로 break그 전에 루프를 종료 할 수 있는 명령문이 있으며 루프 코드를 검토하지 않으면 루프가 표시되지 않습니다 매우 신중하게. 또한 최적화 컴파일러를 포함한 자동화 된 정적 분석기는 루프의 사후 조건을 파악하는 데 어려움을 겪을 수 있습니다.

이것이 Edgar Dijkstra가“고토가 해로운 것으로 간주했다”는 최초의 이유였습니다. 그것은 루프에서 벗어나면 프로그램 상태에 대해 공식적으로 추론하기 어렵게합니다. 나는 break;내 인생에 많은 진술을 썼고 성인이 된 후에는 goto(성능에 중요한 내부 루프의 여러 레벨에서 벗어나서 검색 트리의 다른 브랜치를 계속하기 위해) 썼다 . 그러나 return루프 보다 조건문을 작성할 가능성이 훨씬 높습니다 (루프 후에 코드를 실행하지 않으므로 사후 조건을 따라 잡을 수 없습니다) break.

추신

실제로 동일한 동작을 제공하기 위해 코드를 리팩토링하려면 실제로 더 많은 코드 줄이 필요할 수 있습니다. 리팩토링은 특히 다른 코드에 유효 하거나 condition잘못된 것으로 시작될 수 있음을 증명할 수 있습니다 . 그러나 귀하의 예는 일반적인 경우에 다음과 같습니다.

if ( array.length > 0 ) {
  // Some other code.
}
for ( int i = 1; i < array.length && !condition; i++ ) {
  // Some other code.
}

경우 다른 코드가 한 라이너 아닌, 자신을 반복하지 않도록 당신은 함수로 이동할 수 있습니다, 그리고 당신은 매우 거의 꼬리 재귀 함수로 루프를 리팩토링했습니다.

나는 이것이 당신의 질문의 요점이 아니라는 것을 알고 있으며, 당신은 그것을 간단하게 유지하고있었습니다.


문제는 중단이 코드에 대해 논쟁하기 어렵게 만드는 것이 아니라, 임의의 장소에서 중단하면 코드가 복잡한 것을 만드는 것입니다. 이것이 실제로 필요한 경우 중단으로 인해 논쟁하기가 어렵지 않지만 코드가 복잡한 작업을 수행해야하기 때문입니다.
gnasher729

내가 동의하지 않는 이유는 다음과 같습니다. break명령문 이 없다는 것을 알고 있다면 루프 조건이 무엇인지 알고 해당 조건이 거짓 일 때 루프가 중지된다는 것을 알게됩니다. 있다면 break? 그런 다음 루프가 종료 될 수있는 여러 가지 방법이 있으며 일반적으로 루프 중 하나를 중단 할 수있는 시점을 알아내는 것이 문자 그대로 정지 문제를 해결하는 것입니다. 실제로, 내 큰 걱정은 루프가 있다는 것입니다 보인다 는 루프가 복잡한 논리에 묻혀 가장자리 사건을 간과 한 후 코드를 작성 누구든지, 실제로 한 일을하지만, 같은. 루프 상태의 항목을 놓치기가 어렵습니다.
Davislor

0

예,하지만 구문이 틀렸으므로 나쁜 것입니다 (tm)

희망적으로 당신의 언어는 다음과 같은 것을 지원합니다

while(condition) //condition being a condition which if true you want to continue looping
{
    do thing; //your conditionally executed code goes here
    i++; //you can use a counter if you want to reference array items in order of index
}

2
어쩌면 나는 '조건'에 대해 다른 단어를 사용해야했을 것입니다.이 예에서 문자 그대로 정확히 동일한 조건을 의미한다는 의미는 아닙니다.
Ewan

1
for 루프는 원격으로도 전통적이지 않을뿐만 아니라이 형식의 while 루프가 동등한 for 루프보다 나은 이유는 전혀 없습니다. 사실 대부분의 사람들은 등의 저자로, 나쁘다 말할 것 CPP 핵심 가이드 라인
숀 버튼

2
어떤 사람들은 창의적인 대안을 싫어합니다. 또는 머리에 설정된 것과 다른 방식으로 문제를보고 있습니다. 또는 더 일반적으로, 똑똑한 엉덩이. 나는 당신의 고통을 느낀다!
Martin Maat

1
@sean 미안 친구, 나는 사람들이 그들이 틀렸다는 것을 싫어하는 것을 알고 있지만 난 당신을 es.77 참조
Ewan

2
이것은 while코드의 몬스터를 강조합니다. 예외는 일상 / 일반 코드에 숨겨져 있습니다. 비즈니스 로직은 전면과 중앙에 있으며 반복 메커니즘이 포함되어 있습니다. for루프 대안에 대한 "잠깐만 기다리십시오"반응을 피 합니다. 이 답변 은 문제를 해결합니다. 절대적으로 투표.
radarbob

0

지나치게 복잡한 for성명서를 읽기가 어렵다고 우려되는 경우에는 분명히 유효한 문제입니다. 수직 공간 낭비도 문제입니다 (덜 중요하지만).

(개인적으로 나는 규칙 싫어하는 if문은 항상 크게 여기에 낭비 수직 공간의 원인 인 중괄호가 있어야합니다. 문제가되고 있습니다 낭비 수직 공간을. 사용하여 문제가되지 않습니다 의미 라인과 수직 공간.)

한 가지 옵션은 여러 줄로 나누는 것입니다. for여러 변수와 조건이있는 정말 복잡한 명령문을 사용하는 경우이 작업을 수행해야합니다 . (이것은 수직 공간을 더 잘 사용하여 가능한 한 많은 의미있는 줄을 제공합니다.)

for (
   int i = 0, j = 0;
   i < array.length && !condition;
   i++, j++
) {
   // stuff
}

더 나은 접근 방식은보다 선언적이고 덜 명령적인 형식을 사용하는 것입니다. 언어에 따라 다르거 나 이런 종류의 기능을 사용하려면 고유 한 함수를 작성해야 할 수도 있습니다. 또한 condition실제로 무엇인지에 달려 있습니다. 아마도 배열의 내용에 따라 어떻게 든 변경 될 수 있어야합니다.

array
.takeWhile(condition)  // condition can be item => bool or (item, index) => bool
.forEach(doSomething); // doSomething can be item => void or (item, index) => void

복잡하거나 특이한 for진술을 여러 줄로
나누는 것이이

0

잊어 버린 한 가지 : 루프에서 벗어날 때 (어떻게 구현 되든 가능한 모든 반복을 수행하지는 않음) 일반적으로 루프를 종료하고 싶을뿐만 아니라 왜 이런 일이 발생했는지 알고 싶습니다. . 예를 들어, 항목 X를 찾으면 루프에서 벗어나는 것뿐만 아니라 X가 발견 된 위치와 위치를 알고 싶습니다.

이 상황에서 루프 외부의 조건을 갖는 것은 자연 스럽습니다. 그래서 시작합니다

bool found = false;
size_t foundIndex;

그리고 루프에서 나는 쓸 것이다

if (condition) {
    found = true;
    foundIndex = i;
    break;
}

for 루프로

for (i = 0; i < something && ! found; ++i)

이제 루프의 상태를 확인하는 것은 매우 자연 스럽습니다. "break"문이 있는지 여부는 루프에서 피하려는 추가 처리가 있는지 여부에 따라 다릅니다. 일부 처리가 필요하고 다른 처리가 필요하지 않은 경우

if (! found) { ... }

당신의 루프 어딘가에.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.