`break`와`continue`는 나쁜 프로그래밍 관행입니까?


191

상사는 나쁜 프로그래머가 사용 break하고 반복적으로 사용한다는 것을 무의식적으로 언급합니다 continue.

나는 그들이 이해하기 때문에 항상 사용합니다. 영감을 보여 드리겠습니다.

function verify(object) {
    if (object->value < 0) return false;
    if (object->value > object->max_value) return false;
    if (object->name == "") return false;
    ...
}

여기서 중요한 것은 먼저 함수가 조건이 올바른지 확인한 다음 실제 기능을 실행한다는 것입니다. 루프에도 IMO가 적용됩니다.

while (primary_condition) {
    if (loop_count > 1000) break;
    if (time_exect > 3600) break;
    if (this->data == "undefined") continue;
    if (this->skip == true) continue;
    ...
}

나는 이것이 더 쉽게 읽고 디버깅 할 수 있다고 생각합니다. 그러나 나는 또한 단점을 보지 못한다.


2
어느 것이 무엇을하는지 잊어 버리지 않습니다.

57
아닙니다. 언제 사용해야하는지 아는 것이 핵심입니다. 도구 상자의 도구입니다. 명확하고 간결한 코드를 제공 할 때 사용합니다.
orj

67
이 스타일의 코딩에 대한 나의지지를 충분히 강하게 말할 수는 없다. 여러 수준의 중첩 조건이이 방법보다 훨씬 나쁩니다. 나는 일반적으로 코딩 스타일에 대해 무장하지는 않지만 이것은 거의 나를 깨뜨릴 것입니다.
Emil H

9
분명히 상사는 코드를 작성하지 않습니다. 만약 그렇다면 모든 키워드 (예, 심지어 goto)가 어떤 경우 에는 유용하다는 것을 알 것 입니다.
사키 스크

57
나쁜 프로그래머가 중단을 사용 한다고해서 좋은 프로그래머가 그렇지 않다는 의미는 아닙니다. 나쁜 프로그래머도 가끔 사용합니다.
mouviciel

답변:


240

블록의 시작 부분에서 사용될 때, 첫 번째 검사에서와 같이 사전 조건처럼 작동하므로 좋습니다.

블록 중간에 코드를 사용하면 숨겨진 트랩처럼 작동하므로 나쁩니다.


6
@Klaim : 여러 개의 종료 점이있는 루틴은 제대로 정의되지 않은 루틴이라고 주장 할 수 있습니다. 제대로 고려 된 루틴은 한 가지 일만해야합니다.
bit-twiddler

79
@ bit-twiddler : 이것은 매우 C-ish 사고 방식입니다. 임시 변수는 나중에 수정할 수 있으므로 여기에서 한 줄의 오타가 20 줄 아래로 정교하게 만들어진 결과를 지울 수 있습니다. 그러나 즉시 반환 (또는 중단 또는 계속)은 매우 분명 합니다 . 더 이상 수정 할 수 없다는 것을 알고 있기 때문에 지금 읽기를 중단 할 수 있습니다 . 내 작은 두뇌에 좋으며 실제로 코드를 더 쉽게 조정할 수 있습니다.
Matthieu M.

15
@Matthieu 동의합니다. 블록의 목적을 만족하는 결과를 받으면 블록을 종료하십시오.
Evan Plaice

8
@ bit-twiddler-단일 종료점 원칙은 단일 책임 원칙과 별개입니다. 나는 검사가 항상 WRT를 단일 책임으로하는 ​​것과 분리되어 있다는 데 동의하지 않습니다. 사실 "단일 책임"은 항상 주관적인 용어로 저를 때립니다. 예를 들어, 이차 해법에서 판별자를 계산하는 것이 별도의 책임이어야합니까? 아니면 이차 방정식 전체가 하나의 책임이 될 수 있습니까? 나는 그것이 당신이 차별에 대한 별도의 사용을 가지고 있는지 여부에 달려 있다고 주장합니다.
Steve314

10
그 대답은 어려운 규칙이 아니라 경험의 규칙입니다. 그것은 대부분의 경우에 작동하며 상황에 맞는 경우 자유롭게 중단하십시오.
Klaim

87

Donald Knuth의 1974 년 구조화 된 프로그래밍 (Structured Programming)에서 gos Statements를 읽어 go to보면 구조적으로 바람직한 다양한 용도에 대해 설명합니다 . 여기에는 등가 breakcontinue진술이 포함됩니다 (많은 용도가 go to보다 제한된 구조로 개발되었습니다). 당신의 상사는 크 누스를 나쁜 프로그래머라고 부르는 유형입니까?

(예제는 일반적으로. 관심을 나에게 주신, break그리고 continue코드의 조각에서 하나 개의 항목 하나 개의 출구를 좋아하는 사람들이 싫어하고, 사람의 종류는 여러에 찡그린 얼굴 return문.)


8
단일 진입 점과 종료점을 갖기 위해 기능과 절차를 좋아하는 대부분의 사람들은 Pascal에서 자랐습니다. 파스칼은 내가 처음 배운 언어는 아니지만, 오늘날 코드를 구성하는 방법에 큰 영향을 미쳤습니다. 사람들은 항상 내 Java 코드를 읽는 것이 얼마나 쉬운 지에 대해 언급합니다. 여러 종료점을 피하고 선언을 코드와 혼합하는 것을 피하기 때문입니다. 메소드 상단에 메소드에 사용 된 모든 로컬 변수를 선언하기 위해 최선을 다합니다. 이 방법은 메소드를 간결하게 유지하도록하여 코드가 엉망이되는 것을 피합니다.
비트 트위 들러

5
파스칼에는 또한 중첩 함수가있었습니다. 그냥 말해 ...
Shog9

6
내가 기억하는 것에서, 사람들이 함수에서 여러 개의 return 문을 좋아하지 않는 주된 이유는 디버거가 제대로 처리하지 않았기 때문입니다. 함수의 끝에서 중단 점을 설정하는 것은 정말 고통 스럽지만 이전의 return 문으로 인해 중단 점을 두지 않았습니다. 오늘날 모든 컴파일러에 대해 더 이상 문제가되지 않습니다.
Dunk

28
@ bit-twiddler : 확실하지 않습니다. 저는 오늘도 여전히 파스칼을 사용하고 있으며 일반적으로 "단일 출입구"또는 적어도 그 출구를화물 컬트 프로그래밍으로 간주합니다. 난 그냥 생각 Break, Continue그리고 Exit내 도구 상자의 도구와 같은; 코드를 쉽게 따르기 쉬운 곳에서 사용하고, 읽기 어려운 곳에서는 사용하지 않습니다.
메이슨 휠러

2
@ bit-twiddler : 아멘. 또한 화면에 쉽게 맞는 블록으로 넘어 가면 여러 개의 출구 지점이 훨씬 덜 번거로워집니다.
Shog9

44

나는 그들이 나쁜 생각하지 않습니다. 그들이 나쁘다는 생각은 구조화 된 프로그래밍 시대에서 비롯됩니다. 함수는 단일 진입 점과 단일 종료점을 가져야한다는 개념과 관련이 return있습니다. 즉, 함수 당 하나만 있습니다.

함수가 길고 여러 개의 중첩 루프가있는 경우 의미가 있습니다. 그러나 함수는 짧아야하며 루프와 본문을 짧은 함수로 감싸 야합니다. 일반적으로 함수가 단일 종료점을 갖도록 강요하면 매우 복잡한 논리가 발생할 수 있습니다.

함수가 매우 짧은 경우, 단일 루프가 있거나 최악의 경우 두 개의 중첩 루프가 있고 루프 본문이 매우 짧은 경우 a break또는 a의 기능 이 매우 명확합니다 continue. 여러 return문장이 무엇을하는지도 명확합니다 .

이러한 문제는 Robert C. Martin의 "Clean Code"와 Martin Fowler의 "Refactoring"에서 해결됩니다.


12
"함수를 작게 만들고 작게 만드십시오"-Robert C. Martin. 나는 이것이 놀랍게 잘 작동한다는 것을 알았다. 기능에서 설명하는 주석이 필요한 함수에 코드 블록이 표시 될 때마다 설명이 포함 된 별도의 함수로 묶습니다. 몇 줄 뿐이고 한 번만 사용하더라도 마찬가지입니다. 이 방법은 중단 / 계속 또는 여러 반품과 관련된 대부분의 문제를 제거합니다.
Dima

2
@ Mikhail : Cyclomatic의 복잡성은 일반적으로 SLOC와 밀접한 상관 관계가 있습니다. 즉, "긴 함수를 작성하지 마십시오"라는 조언을 단순화 할 수 있습니다.
John R. Strohm

3
단일 출구 점에 대한 아이디어는 널리 잘못 해석됩니다. 옛날 옛적에 함수는 호출자를 반환 할 필요가 없었습니다. 그들은 다른 곳으로 돌아갈 수있었습니다. 이것은 일반적으로 어셈블리 언어로 수행되었습니다. 포트란은이를 위해 특별한 구성을 가지고있었습니다. ampersand 앞에 오는 명령문 번호를 전달할 수 있으며, CALL P(X, Y, &10)오류가 발생하면 함수는 호출 지점으로 돌아 가지 않고 해당 명령문으로 제어를 전달할 수 있습니다.
케빈 클라인

예를 들어 루아와 같이 @kevincline.
Qix

1
@cjsimon 당신은 그것을 얻었다. 기능 만 작아야하는 것은 아닙니다. 수업도 작아야합니다.
Dima

39

나쁜 프로그래머는 절대적으로 (시스와 마찬가지로) 말합니다. 훌륭한 프로그래머는 가능한 가장 명확한 솔루션을 사용합니다 ( 다른 모든 것들은 동일 함 ).

break 및 continue를 사용하면 코드를 따르기가 어렵습니다. 그러나 그것들을 대체하면 코드를 따르기가 더 어려워지면 나쁜 변화입니다.

당신이 준 예는 분명히 휴식과 계속이 더 우아한 것으로 대체되어야하는 상황입니다.


예, 종료 할 사례의 예를 제공하기 위해 조건 수를 과장했습니다.
Mikhail

9
제안한 대체 코드의 예는 무엇입니까? 나는 그것이 가드 진술의 다소 합리적인 예라고 생각했다.
simgineer

"가장 명확한 해결책"이 항상 가능한 것 같습니다. 어떻게 "가장 명확한"솔루션이 없을 수 있습니까? 그러나 나는 절대적인 사람이 아니므로 아마도 당신이 옳을 것입니다.

@nocomprende 나는 당신이 무엇을 얻고 있는지 잘 모르겠습니다. 여기서 "가능한"은 최상의 솔루션이 존재하지 않음을 나타내지 않습니다. 완벽하고 완벽한 선명도는 문제가 아닙니다. 결국 주관적입니다.
Matthew 읽기

22

대부분의 사람들은 행동을 쉽게 예측할 수 없기 때문에 그것이 나쁜 생각이라고 생각합니다. 코드를 읽는 while(x < 1000){}중이고 x> = 1000까지 실행될 것이라고 가정하면 중간에 중단이 있으면 사실이 아니므로 실제로는 신뢰할 수 없습니다. 루핑 ...

그것은, 확인 : 그것은 사람들이 GOTO를 좋아하지 않아 같은 이유 도 사용할 수 있지만, 그것은 또한 코드 섹션을 섹션에서 무작위로 도약 godawful 스파게티 코드로 이어질 수 있습니다.

나 자신을 위해, 둘 이상의 조건에서 끊어진 루프를 수행하려는 경우, while(x){}헤어져야 할 때 X를 false로 전환합니다. 최종 결과는 동일하며 코드를 읽는 사람은 누구나 X의 가치를 바꾼 것을 자세히 살펴볼 것입니다.


2
+1은 잘 말했고 while(notDone){ }접근 방식에 대해 +1 (다른 작업을 수행 할 수있는 경우)입니다 .
FrustratedWithFormsDesigner

5
Mikhail : 중단의 문제는 루프의 최종 조건이 단순히 한 곳에만 언급되지 않는다는 것입니다. 따라서 루프 후 사후 조건을 예측하기가 어렵습니다. 이 사소한 경우 (> = 1000) 어렵지 않습니다. 많은 if 문과 다른 중첩 수준을 추가하면 루프의 사후 조건을 결정하는 것이 매우 어려워 질 수 있습니다.
S.Lott

S. 로트는 머리에 못을 hit 다. 반복을 제어하는 ​​표현식에는 반복을 계속하기 위해 충족해야하는 모든 조건이 포함되어야합니다.
bit-twiddler

6
교체 break;로하면 x=false;코드를 더욱 명확하지 않습니다. 당신은 여전히 ​​그 진술에 대해 본문을 검색해야합니다. 그리고 x=false;당신이 x=true;더 이상 타격을받지 않는지 확인해야합니다 .
Sjoerd

14
사람들이 "x를보고 y를 가정하지만, z를 가정하면 그 가정이 유지되지 않는다"고 말할 때 "그 바보 같은 가정을하지 마십시오"라고 생각하는 경향이 있습니다. 많은 사람들이 " while (x < 1000)1000 번 실행한다고 가정 할 때"로 단순화했습니다 . 글쎄, 처음에 0 이더라도, 그것이 잘못된 이유는 여러 가지 x가 있습니다. 예를 들어, 누가 말한다 x는 루프 중에 정확히 한 번 증가하고 다른 방식으로 수정되지 않습니까? 자신의 가정에도 불구하고 무언가 세트 x >= 1000가 루프가 종료되는 것을 의미하지는 않습니다. 조건이 확인되기 전에 범위 내에서 다시 설정 될 수 있습니다.
Steve314

14

예. break 문없이 프로그램을 다시 작성할 수 있습니다 (또는 동일한 작업을 수행하는 루프 중간에서 반환). 그러나 일반적으로 프로그램을 이해하기 어렵게하는 추가 변수 및 / 또는 코드 복제를 도입해야 할 수도 있습니다. 파스칼 (프로그래밍 언어)은 특히 초보자 프로그래머에게는 매우 나빴습니다. 당신의 상사는 기본적으로 파스칼의 제어 구조로 프로그램하기를 원합니다. Linus Torvalds가 당신의 신발에 있다면, 아마도 당신의 상사에게 가운데 손가락을 보여줄 것입니다!

Kosaraju의 제어 구조 계층 구조라는 컴퓨터 과학 결과가 있습니다.이 구조는 1973 년으로 거슬러 올라가며 1974 년 고 토스에 대한 Knuth의 유명한 논문에서 언급되었습니다. (Knuth의 논문은 이미 David Thornley가 위에서 권장했습니다. .) 어떤 S. 라오 코사 라주는 1973 년에 증명하는 것은 깊이의 멀티 레벨 휴식이 모든 프로그램을 다시 쓸 수는 없습니다이다 N 이상의 휴식 깊이 이하의 프로그램에 n 개의 추가 변수를 도입하지 않고있다. 그러나 그것은 단지 순수한 이론적 결과라고 가정 해 봅시다. (몇 가지 추가 변수를 추가 하시겠습니까?! 확실히 상사를 기쁘게하기 위해 그렇게 할 수 있습니다 ...)

소프트웨어 엔지니어링 관점에서 훨씬 더 중요한 것은 1995 년 Eric S. Roberts의 Loop Exits and Structured Programming : Debing the the Debate ( http://cs.stanford.edu/people/eroberts/papers/SIGCSE-) 라는 최신 논문입니다 . 1995 / LoopExits.pdf ). Roberts는 다른 사람이 수행하기 전에 수행 한 몇 가지 경험적 연구를 요약합니다. 예를 들어, CS101 유형의 학생 그룹이 배열에서 순차 검색을 구현하는 함수에 대한 코드를 작성하도록 요청 받았을 때, 연구의 저자는 중단 / 반환 / 고토를 사용하여 시작을 종료 한 학생에 대해 다음과 같이 말했습니다. 요소가 발견 될 때 순차 검색 루프 :

[이 스타일]을 사용하여 프로그램을 시도하여 잘못된 솔루션을 만든 한 사람을 아직 찾지 못했습니다.

로버츠는 또한 다음과 같이 말합니다.

for 루프에서 명시적인 리턴을 사용하지 않고 문제를 해결하려고 시도한 학생들은 훨씬 덜 나빴습니다.이 전략을 시도하는 42 명의 학생 중 7 명만이 올바른 솔루션을 생성 할 수있었습니다. 이 수치는 20 % 미만의 성공률을 나타냅니다.

예, CS101 학생보다 경험이 많을 수 있지만 break 문을 사용하지 않고 (또는 루프 중간에서 리턴 / 가로 이동) 결국 명목상 잘 구성되었지만 추가 논리 측면에서 충분히 털이있는 코드를 작성합니다 변수와 코드 복제는 아마도 여러분 자신의 상사 코딩 스타일을 따르려고 할 때 누군가 자신에게 논리 버그를 넣을 것이라는 점입니다.

또한 Roberts의 논문은 일반 프로그래머가 훨씬 더 접근 할 수 있으므로 Knuth의 논문보다 더 잘 읽습니다. 또한 더 짧고 더 좁은 주제를 다룹니다. CS 유형이 아닌 관리인이라도 상사에게 추천 할 수도 있습니다.


2
구조화 된 프로그래밍은 수년 동안 저의 접근 방식 이었지만, 지난 몇 년간 첫 번째 기회에서 명시 적 종료를 완전히 사용하도록 전환했습니다. 이를 통해 실행 속도가 빨라지고 무한 루프 (매달림)를 발생시키는 데 사용되는 논리 오류가 거의 제거됩니다.
DocSalvager

9

이러한 나쁜 습관 중 하나를 사용하는 것은 고려하지 않지만 동일한 루프 내에서 너무 많이 사용하면 루프에서 사용되는 논리를 다시 생각해야합니다. 드물게 사용하십시오.


:) 예, 제가 제공 한 예는 개념적이었습니다
Mikhail

7

당신이 준 예제는 중단하거나 계속할 필요가 없습니다.

while (primary-condition AND
       loop-count <= 1000 AND
       time-exec <= 3600) {
   when (data != "undefined" AND
           NOT skip)
      do-something-useful;
   }

귀하의 예에서 4 줄에 대한 나의 '문제'는 모두 같은 수준에 있지만 다른 일을한다는 것입니다. 일부 중단, 일부 계속 ... 각 줄을 읽어야합니다.

내 중첩 된 접근 방식에서는 더 깊게 갈수록 코드가 더 유용합니다.

그러나 내부 깊은 곳에서 루프를 중지 해야하는 이유 (기본 조건 제외)를 발견하면 중단 또는 반환에 사용됩니다. 최상위 조건에서 테스트 할 추가 플래그를 사용하는 것이 좋습니다. 휴식 / 복귀가 더 직접적입니다. 또 다른 변수를 설정하는 것보다 의도를 더 잘 나타냅니다.


+1 그러나 실제로 <비교 <=는 OPs 솔루션과 일치 해야합니다
El Ronnoco

3
대부분의 경우 흐름 제어를 관리하기 위해 중단 / 반환을 사용해야 할 정도로 깊으면 기능 / 방법이 너무 복잡합니다.
bit-twiddler

6

"나쁜"은 사용 방법에 따라 다릅니다. 나는 일반적으로 알고리즘의 리팩토링을 통해 저장할 수없는 사이클을 저장할 때만 루프 구성에서 중단을 사용합니다. 예를 들어 특정 속성의 값이 true로 설정된 항목을 찾는 컬렉션을 순환합니다. 알아야 할 모든 항목 중 하나에이 속성이 true로 설정되어 있으면 해당 결과를 얻은 후에는 루프를 적절히 종료하는 것이 좋습니다.

중단을 사용하여 코드를 읽기 쉽고, 실행 시간을 단축 시키거나 처리주기를 크게 단축시킬 수 없다면 사용하지 않는 것이 가장 좋습니다. 나는 나를 따르는 사람이 쉽게 내 코드를보고 무슨 일이 일어나고 있는지 파악할 수 있도록 가능한 한 "최소 공통 분모"로 코딩하는 경향이 있습니다 (항상 성공하지는 않습니다). 홀수 진입 점 / 출구 점을 도입하므로 나누기가 줄어 듭니다. 잘못 사용 된 그들은 "고토 (goto)"구절과 매우 유사하게 행동 할 수있다.


나는 두 가지 점에 동의합니다! 두 번째 요점은 영어처럼 읽히기 때문에 원래 게시물을 따르는 것이 더 쉽다고 생각합니다. 1 if 문에 조건의 조합이있는 경우 if를 true로 실행하기 위해 어떤 일이 발생하는지 알아내는 것은 거의 해독입니다.
Mikhail

@ Mikhail : 당신이 제공 한 샘플은 특정 사실주의에 대한 이타 적입니다. 내가 알다시피, 그 샘플은 명확하고 간결하며 읽기 쉽습니다. 대부분의 루프는 그렇지 않습니다. 대부분의 루프에는 수행중인 다른 종류의 논리와 훨씬 더 복잡한 조건이 있습니다. 이러한 경우 읽기 / 쓰기를 수행 할 때 논리가 흐려 지므로 중단 / 계속이 최상의 사용법이 아닐 수 있습니다.
Joel Etherton

4

물론 아닙니다 ... 그렇습니다. goto프로그램의 구조를 악화시키고 제어 흐름을 이해하기가 어렵 기 때문에 사용 이 나쁩니다.

그러나 같은 문장의 사용 break과는 continue전혀 나쁜 프로그래밍 연습으로 간주 요즘이 아니라 절대적으로 필요하다.

그리고 또한 어려운 일이 아니다의 사용 제어 흐름을 이해 break하고 continue. 같은 구조에서 문 절대적으로 필요하다.switchbreak


2
1981 년에 C를 처음 배운 이후로 "continue"를 사용하지 않았습니다. continue 문으로 우회 된 코드가 조건부 제어 문으로 래핑 될 수 있으므로 불필요한 언어 기능입니다.
bit-twiddler

12
필자는 코드가 화살표 코드가되지 않도록하기 때문에 계속 사용하는 것을 선호합니다. goto type 문보다 화살표 코드가 더 싫습니다. 또한 "이 문장이 참이면이 루프의 나머지 부분을 건너 뛰고 다음 반복을 계속하십시오"라고 읽었습니다. for 루프의 맨 처음에있을 때 매우 유용합니다 (while 루프에서는 유용하지 않음).
jsternberg 2016 년

@jsternberg 승리를 위해! :-)
Notinlist

3

핵심 개념은 프로그램을 의미 적으로 분석 할 수 있다는 것입니다. 단일 항목과 단일 종료가있는 경우 가능한 경로를 표시하는 데 필요한 수학은 분기 경로를 관리해야하는 경우보다 훨씬 쉽습니다.

부분적으로이 어려움은 코드에 대해 개념적으로 추론 할 수 있음을 반영합니다.

솔직히 두 번째 코드는 명확하지 않습니다. 뭐하는거야? 계속 '계속'합니까, 아니면 루프를 '다음'입니까? 나도 몰라 적어도 첫 번째 예는 분명합니다.


관리자가이를 사용해야하는 프로젝트에서 작업 할 때 플로우 차트를 사용하여 그 사용법을 기억해야했고 여러 종료 경로가 더 혼란스러운 코드를
만들었습니다

"Frankly"의견은 구문입니다. "next"는 펄입니다. 일반 언어는 "continue"를 사용하여 "이 루프 건너 뛰기"를 의미합니다
Mikhail

@Mik, 아마도 "이 반복 건너 뛰기"가 더 나은 설명 일 것입니다. IM Pedantic 박사
Pete Wilson

@ Mikhail : 물론입니다. 그러나 많은 언어로 작업 할 때 언어간에 구문이 공통적이지 않으면 오류가 발생할 수 있습니다.
Paul Nathan

그러나 수학은 프로그래밍 이 아닙니다 . 코드는 수학보다 표현력이 좋습니다. 나는 (즉. 여기서 휴식 / 리턴 코드가 더 잘 수행 할 수 있습니다) 단일 입력 / 단일 출구 플로우 차트가 좋네요하지만 비용으로 보이게 만들 수 있다는 것을?
Evan Plaice

3

두 번째 코드 스 니펫을

while (primary_condition && (loop_count <= 1000 && time_exect <= 3600)) {
    if (this->data != "undefined" && this->skip != true) {
        ..
    }
}

간결한 이유가 아니라-실제로는 이것이 더 읽기 쉽고 누군가가 무슨 일이 일어나고 있는지 이해할 수 있다고 생각합니다. 일반적으로 루프의 조건은 몸 전체에 흩어지지 않는 루프 조건 내에 순수하게 포함되어야합니다. 그러나 몇 가지 상황이 있습니다 breakcontinue가독성을 도울 수는. 내가 추가 할 수있는 break것보다 continue: D


"실제로 읽기가 더 쉽다고 생각합니다"라는 의견에 동의하지 않습니다. 위의 코드와 동일한 목적을 달성합니다. 나는 지금까지 '브레이크'를 단락 연산자라고 생각한 적이 없지만 완벽하게 이해됩니다. "일반적으로 루프 조건은 루프 조건 내에 순전히 포함되어야합니다"와 관련하여 루프 정의에 조건부 논리를 삽입 할 방법이 없기 때문에 foreach 루프를 처리 할 때 어떻게해야합니까?
Evan Plaice

@Evan 조건은 foreach컬렉션의 모든 항목을 반복 하기 때문에 루프 에는 적용되지 않습니다 . for루프는 조건부 끝 지점을하지 말았어야 점에서 유사하다. 조건부 엔드 포인트가 필요한 경우 while루프 를 사용해야합니다 .
El Ronnoco

1
@Evan 나는 당신의 요점을 알 수 있습니다-즉 'foreach 루프에서 벗어나려면 어떻게해야합니까?' - break루프에서 내 의견으로는 최대 하나만 있어야합니다 .
El Ronnoco

2

나는 당신의 상사와 동의하지 않습니다. 적절한 장소 breakcontinue사용 장소 가 있습니다. 실제로 예외 및 예외 처리가 최신 프로그래밍 언어에 도입 된 이유는을 사용하여 모든 문제를 해결할 수 없기 때문 structured techniques입니다.

참고로 여기서 종교 토론을 시작하고 싶지 않지만 다음과 같이 코드를 더 읽기 쉽도록 재구성 할 수 있습니다.

while (primary_condition) {
    if (loop_count > 1000) || (time_exect > 3600) {
        break;
    } else if ( ( this->data != "undefined") && ( !this->skip ) ) {
       ... // where the real work of the loop happens
    }
}

다른쪽에

( flag == true )변수가 이미 부울 인 경우 부울 값에 원하는 대답이있을 때 발생 해야하는 추가 비교를 소개하기 때문에 조건부 에서 사용하는 것을 개인적으로 싫어합니다. 물론 컴파일러가 확실하지 않은 경우 추가 비교를 최적화하십시오.


나는이 질문에 몇 년 동안 혼란스럽게했습니다. 당신의 길 ( 'if (flag) {...}')은 훨씬 더 간결하며 아마도 '전문적'또는 '전문가'처럼 보입니다. 그러나, 그것은 종종 독자 / 유지 보수자가 작문이 의미하는 바를 기억하기 위해 잠시 자신을 방해해야한다는 것을 의미합니다. 그리고 테스트의 의미를 확인하십시오. 현재는 더 나은 문서 인 것처럼 보이기 때문에 'if (flag == true) {...}'를 사용하고 있습니다. 다음 달? 사브르를 조용히?
Pete Wilson

2
@Pete-용어는 간결 하지 않고 우아 합니다. 원하는 모든 것을 와플 링 할 수 있지만 독자 / 유지 보수자가 boolean간결하고 우아한 용어의 의미가 무엇인지 이해하지 못하는 것이 걱정된다면 더 현명한
관리인을

@Pete, 나는 또한 생성 된 코드에 대한 진술을지지한다. 식의 부울 값을 평가하기 전에 플래그를 상수 값과 비교하여 한 번 더 비교를 수행합니다. 플래그 변수를 이전보다 더 어렵게 만드는 이유는 무엇입니까? 플래그 변수에는 이미 원하는 값이 있습니다!
Zeke Hansell

좋은 일 +1. 이전 예보다 훨씬 더 우아합니다.
Evan Plaice

2

나는 당신의 상사에 동의합니다. 그들은 사이클로 틱 복잡성이 높은 방법을 생산하기 때문에 나쁘다. 이러한 방법은 읽기 어렵고 테스트하기가 어렵습니다. 다행히도 쉬운 해결책이 있습니다. 루프 본문을 별도의 방법으로 추출하십시오. 여기서 "계속"은 "반환"이됩니다. "반환"이 끝난 후 "반환"이 더 좋습니다. 지역 상태에 대해 걱정할 필요가 없습니다.

"break"의 경우 "break"를 "return"으로 대체하여 루프 자체를 별도의 메소드로 추출하십시오.

추출 된 메소드에 많은 수의 인수가 필요한 경우 클래스를 추출한다는 표시입니다. 컨텍스트 오브젝트로 수집하십시오.


0

여러 루프 내부에 깊게 중첩 된 경우에만 문제가 있다고 생각합니다. 어떤 루프를 끊고 있는지 알기가 어렵습니다. 계속 진행하기가 어려울 수도 있지만 실제 고통은 휴식에서 비롯된다고 생각합니다. 논리는 따르기가 어려울 수 있습니다.


2
실제로, 당신이 제대로 들여 쓰기, 쉽게 그 진술의 의미를 내면화하고 너무 졸리지 않은지 쉽게 볼 수 있습니다.

@delnan-그것은 많은 가정이다;)
davidhaskins

2
네, 특히 마지막입니다.
Michael K

글쎄, # 1은 진지한 프로그래밍에 필요하다. # 2는 프로그래머라고 불리는 모든 사람에게 기대된다. # 3은 일반적으로 매우 유용하다;)

일부 언어 (내가 아는 스크립트 만 지원) break 2; 다른 사람들을 위해, 임시 bool 플래그가 사용되는 것 같습니다
Mikhail

0

다음 예제와 같이 위장 된 goto로 사용되지 않는 한 :

do
{
      if (foo)
      {
             /*** code ***/
             break;
      }

      if (bar)
      {
             /*** code ***/
             break;
      }
} while (0);

난 괜찮아 (제작 코드 meh에서 볼 수있는 예)


이와 같은 경우에 함수를 작성하도록 권장 하시겠습니까?
Mikhail

예, 가능하지 않으면 평범한 고토입니다. 내가 볼 때, 나는 점프를 시뮬레이션하기위한 문맥이 아니라 반복을 생각한다.
SuperBloup

동의 오, 난 그냥 당신이 그것을 할 거라고 방법을 요구했다 : 컴퓨터 과학자들은 반복적으로 수행
미하일

0

나는 이러한 스타일 중 하나를 좋아하지 않습니다. 내가 선호하는 것은 다음과 같습니다.

function verify(object)
{
    if not (object->value < 0) 
       and not(object->value > object->max_value)
       and not(object->name == "") 
       {
         do somethign important
       }
    else return false; //probably not necessary since this function doesn't even seem to be defined to return anything...?
}

나는 return함수를 중단하기 위해 사용 하는 것을 정말로 좋아하지 않는다 . 의 남용 인 것 같습니다 return.

break또한 사용하기 가 항상 명확한 것은 아닙니다.

더 나은 아직 :

notdone := primarycondition    
while (notDone)
{
    if (loop_count > 1000) or (time_exect > 3600)
    {
       notDone := false; 
    }
    else
    { 
        skipCurrentIteration := (this->data == "undefined") or (this->skip == true) 

        if not skipCurrentIteration
        {
           do something
        } 
        ...
    }
}

적은 중첩과 복잡한 조건은 변수로 리팩토링됩니다 (실제 프로그램에서는 분명히 더 나은 이름을 가져야합니다 ...)

(위의 모든 코드는 의사 코드입니다)


11
위에서 입력 한 것보다 3 단계의 중첩을 선호합니까?
Mikhail

@ Mikhail : 예 또는 조건 결과를 변수에 할당합니다. breakand 의 논리보다 이해하기가 훨씬 쉽다는 것을 알았습니다 continue. 비정상적으로 루프를 끝내면 이상한 느낌이 들며 마음에 들지 않습니다.
FrustratedWithFormsDesigner

1
아이러니하게도, 당신은 내 조건을 잘못 읽었습니다. continue기능이 다음 루프로 넘어가는 것을 의미합니다. "집행 계속"
미하일

@ 미카 일 : 아. 나는 그것을 자주 사용하지 않으며 그것을 읽을 때 의미에 혼란스러워합니다. 내가 그것을 좋아하지 않는 또 다른 이유. : P 업데이트 할 시간을주세요 ...
FrustratedWithFormsDesigner

7
중첩이 너무 많으면 가독성이 손상됩니다. '난 그냥 선생님이있어 - 그리고 때때로 휴식을 피하고 / 계속 당신의 코드가 무엇을하고 있는지 잘못 해석 될 수 있습니다 조건부 테스트에 논리를 반전의 필요성, 도입
지크 Hansell

0

아니요 . 문제를 해결하는 방법이며 다른 해결 방법이 있습니다.

많은 현재의 주류 언어 (자바, .NET (C # + VB), PHP, 직접 작성)는 "break"및 "continue"를 사용하여 루프를 건너 뜁니다. 둘 다 "구조화 된 goto (s)"문장입니다.

그들없이:

String myKey = "mars";

int i = 0; bool found = false;
while ((i < MyList.Count) && (not found)) {
  found = (MyList[i].key == myKey);
  i++;   
}
if (found)
  ShowMessage("Key is " + i.toString());
else
  ShowMessage("Not found.");

그들과 함께 :

String myKey = "mars";

for (i = 0; i < MyList.Count; i++) {
  if (MyList[i].key == myKey)
    break;
}
ShowMessage("Key is " + i.toString());

"break"및 "continue"코드는 더 짧으며 일반적으로 "while"문장을 "for"또는 "foreach"문장으로 바꿉니다.

두 경우 모두 코딩 스타일의 문제입니다. 자세한 스타일을 사용하면 코드를 더 많이 제어 할 수 있기 때문에 사용하지 않는 것이 좋습니다.

저는 실제로 일부 문장에서 문장을 사용해야하는 프로젝트에서 일합니다.

어떤 개발자들은 그들이 제왕 절개가 아니라고 생각할 수도 있지만, 우리가 그것들을 제거해야한다면, "while"과 "do while"을 제거해야합니다.

결론, 내가 사용하지 않으려는 경우에도 나쁜 프로그래밍 관행이 아니라 옵션이라고 생각합니다.


까다롭게 죄송하지만 두 번째 예제에는 키를 찾을 수 없을 때 출력이 누락됩니다 (물론 훨씬 짧아 보입니다).
FrustratedWithFormsDesigner

2
첫 번째 예제는 키가 목록의 마지막 키인 경우에만 작동합니다.
Mikhail

@FrustratedWithFormsDesigner가 정확합니다. 나는 그 방법이 바람직한 이유를 나타 내기 위해 purpouse를
썼다

그러나 의미가 다른 두 개의 루틴이 있습니다. 따라서 논리적으로 동일하지 않습니다.
bit-twiddler

2
두 번째 예에는 구문과 논리의 두 가지 버그가 있습니다. 1. 반복자가 for 루프 범위 밖에서 선언되지 않기 때문에 컴파일되지 않습니다 (따라서 문자열 출력에서는 사용할 수 없습니다). 2. 반복자가 루프 외부에서 선언 되었더라도 컬렉션에서 키를 찾지 못하면 문자열 출력은 목록에서 마지막 항목의 키를 인쇄합니다.
Evan Plaice

0

나는 반대 continue하고 break원칙적으로는 아니지만, 그것들은 매우 낮은 수준의 구조이며 종종 더 나은 것으로 대체 될 수 있다고 생각합니다.

여기서는 C #을 예로 사용하고 컬렉션을 반복하려는 경우를 고려하지만 일부 술어를 충족시키는 요소 만 원하며 최대 100 회 이상 반복하고 싶지 않습니다.

for (var i = 0; i < collection.Count; i++)
{
    if (!Predicate(item)) continue;
    if (i >= 100) break; // at first I used a > here which is a bug. another good thing about the more declarative style!

    DoStuff(item);
}

이것은 정말 깨끗해 보입니다. 이해하기 어렵지 않습니다. 그래도 더 선언적으로 많은 것을 얻을 수 있다고 생각합니다. 다음과 비교하십시오.

foreach (var item in collection.Where(Predicate).Take(100))
    DoStuff(item);

Where 및 Take 호출이이 방법을 사용해서는 안됩니다. 컬렉션이이 메소드에 전달되기 전에이 필터링을 수행해야 할 수도 있습니다. 어쨌든, 저수준의 물건에서 벗어나 실제 비즈니스 로직에 더 집중함으로써 실제로 우리가 실제로 관심있는 것을 더 명확하게합니다. 코드를 우수한 설계 관행에 더 잘 부합하는 응집성 모듈로 쉽게 분리 할 수 ​​있습니다. 의 위에.

코드의 일부 부분에는 하위 수준의 내용이 여전히 존재하지만 비즈니스 문제에 대해 추론하는 데 사용할 수있는 정신 에너지가 필요하기 때문에 가능한 한 숨기고 싶습니다.


-1

Code Complete 에는 goto루틴 또는 루프에서의 다중 리턴 사용 및 사용에 대한 유용한 섹션이 있습니다.

일반적으로 나쁜 습관이 아닙니다. break또는 continue다음에 무슨 일이 일어나는지 정확히 말하십시오. 그리고 나는 이것에 동의합니다.

Steve McConnell (Code Complete의 저자)은 다양한 goto문장 을 사용할 때의 장점을 보여주기 위해 거의 동일한 예제를 사용 합니다.

그러나 과도하게 사용 break하거나 continue복잡하고 유지 관리 할 수없는 소프트웨어로 이어질 수 있습니다.

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