로부터 코드 전체 책 다음 인용 온다 :
"일반적인 경우
if는else"
즉, 표준 경로에서 예외 / 편차가 발생해야합니다 else.
그러나 Pragmatic Programmer 는 "초기 충돌"(p. 120)을 지시합니다.
어떤 규칙을 따라야합니까?
if지점 중 하나가 반환되면 먼저 사용하십시오. else나머지 코드는 피하십시오 . 사전 조건이 실패한 경우 이미 반환했습니다. 코드는 읽기 쉽고 들여 쓰기가 적습니다 ...
로부터 코드 전체 책 다음 인용 온다 :
"일반적인 경우
if는else"
즉, 표준 경로에서 예외 / 편차가 발생해야합니다 else.
그러나 Pragmatic Programmer 는 "초기 충돌"(p. 120)을 지시합니다.
어떤 규칙을 따라야합니까?
if지점 중 하나가 반환되면 먼저 사용하십시오. else나머지 코드는 피하십시오 . 사전 조건이 실패한 경우 이미 반환했습니다. 코드는 읽기 쉽고 들여 쓰기가 적습니다 ...
답변:
"Crash early"은 어떤 코드 줄이 텍스트보다 먼저 나오는지에 관한 것이 아닙니다. 처리 가능한 초기 단계에서 오류를 감지하여 실수로 이미 결함이있는 상태를 기반으로 의사 결정 및 계산을하지 않도록 지시합니다 .
에서 if/ else둘 다에 "이전"또는 "이상"공정을 구성하는 말했다 수 있도록 구조의 블록 중 하나만이 실행된다. 따라서 주문 방법은 가독성의 문제이며, "실패"는 결정에 들어 가지 않습니다.
if/else구조에서는 아마 중요하지 않습니다. 그러나 루프에서 호출되거나 각 블록에 많은 명령문이있는 것은 가장 일반적인 조건으로 먼저 더 빨리 실행될 수 있습니다.
귀하의 경우 else문 만 실패 코드를 포함, 대부분의 경우는 없을 것이다.
이것을하는 대신 :
if file.exists() :
if validate(file) :
# do stuff with file...
else :
throw foodAtMummy
else :
throw toysOutOfPram
이 작업을 수행
if not file.exists() :
throw toysOutOfPram
if not validate(file) :
throw foodAtMummy
# do stuff with file...
단순히 오류 검사를 포함하기 위해 코드를 깊이 중첩하고 싶지는 않습니다.
그리고 다른 사람들이 이미 언급했듯이 두 가지 조언은 모순되지 않습니다. 하나는 실행 순서 에 관한 것이고 다른 하나는 코드 순서 에 관한 것 입니다.
if블록 에 정상적인 흐름을 유지하고 블록에 예외적 인 흐름을 else적용 하라는 조언이 적용되지 않습니다 else. 이와 같은 보호문은 대부분의 코딩 스타일에서 오류 조건을 처리하기 위해 선호되는 형식입니다.
둘 다 따라야합니다.
"Crash early"/ fail early advice는 가능한 빨리 오류가 있는지 입력을 테스트해야한다는 것을 의미합니다.
예를 들어, 분석법이 양수 (> 0)로 간주되는 크기 나 개수를 받아 들인 경우 조기 조언 실패는 알고리즘이 말이되지 않는 것을 기다리지 않고 분석법의 시작 부분에서 해당 조건을 테스트 함을 의미합니다. 결과.
정상적인 경우를 우선으로하는 조언은 조건을 테스트 할 경우 가장 가능성이 높은 경로가 우선임을 의미합니다. 이는 프로세서의 분기 예측이 더 낫기 때문에 성능과 가독성에 도움이됩니다. 일반적인 경우에 함수가 수행하는 작업을 알아낼 때 코드 블록을 건너 뛸 필요가 없기 때문입니다.
이 조언은 if (!precondition) throw코드를 읽는 동안 건너 뛸 오류 처리가 없기 때문에 전제 조건을 테스트하고 즉시 어설 션 또는 구문 을 사용하여 구제 할 때 적용되지 않습니다 .
if(cond){/*more likely code*/}else{/*less likely code*/}보다 빨리 실행됩니다 if(!cond){/*less likely code*/}else{/*more likely code*/}. 지점 예측이 문 if또는 else문에 편향되지 않고 역사 만 고려 한다고 생각 합니다. 따라서 else발생 가능성이 더 높으면이를 정확하게 예측할 수 있어야합니다. 이 가정이 거짓입니까?
@JackAidley가 이미 그 요점을 말했다고 생각 하지만 다음과 같이 공식화하겠습니다.
규칙적인 코드 흐름에는 다음이 있습니다.
if (condition) {
statement;
} else if (less_likely_condition) {
less_likely_statement;
} else {
least_likely_statement;
}
more_statements;
"초기 오류"사례에서 코드는 갑자기 다음과 같이 읽습니다.
/* demonstration example, do NOT code like this */
if (condition) {
statement;
} else {
error_handling;
return;
}
이 패턴을 발견하는 경우 - a는 return에 else(또는 if문제의 코드는 않도록) 블록, 즉시 재 작업 하지 이 else블록 :
/* only code like this at University, to please structured programming professors */
function foo {
if (condition) {
lots_of_statements;
}
return;
}
현실 세계에서…
/* code like this instead */
if (!condition) {
error_handling;
return;
}
lots_of_statements;
이것은 너무 깊이 중첩 방지 및 은 "초기 탈옥"경우 (마음을 유지하는 데 도움이 -하고 코드 흐름 - 청소)을 충족 하고 (가) "는에 가능성이 일을 넣어 위반하지 않는 if단순히 어떤이 없기 때문에 일부" else부분 .
C 정리비슷한 질문에 대한 답변에서 영감을 얻었습니다 (이 잘못됨). C로 정리하는 방법은 다음과 같습니다. 하나 또는 두 개의 출구 지점을 사용할 수 있습니다. 여기에는 두 개의 출구 지점이 있습니다.
struct foo *
alloc_and_init(size_t arg1, int arg2)
{
struct foo *res;
if (!(res = calloc(sizeof(struct foo), 1)))
return (NULL);
if (foo_init1(res, arg1))
goto err;
res.arg1_inited = true;
if (foo_init2(&(res->blah), arg2))
goto err;
foo_init_complete(res);
return (res);
err:
/* safe because we use calloc and false == 0 */
if (res.arg1_inited)
foo_dispose1(res);
free(res);
return (NULL);
}
정리가 덜 필요한 경우 하나의 종료점으로 축소 할 수 있습니다.
char *
NULL_safe_strdup(const char *arg)
{
char *res = NULL;
if (arg == NULL)
goto out;
/* imagine more lines here */
res = strdup(arg);
out:
return (res);
}
goto당신이 그것을 다룰 수 있다면, 이 사용 은 완벽하게 좋습니다. 사용 goto하지 않는 것이 좋은지, 수용 가능한지, 나쁜지, 스파게티 코드 등을 스스로 결정할 수없는 사람들을 대상으로합니다.
위의 예외는 예외없이 언어에 대해 이야기하며, 나는 나 자신을 선호합니다 (명시 적 오류 처리를 훨씬 잘하고 훨씬 덜 놀라게 사용할 수 있습니다). igli를 인용하려면 :
<igli> exceptions: a truly awful implementation of quite a nice idea.
<igli> just about the worst way you could do something like that, afaic.
<igli> it's like anti-design.
<mirabilos> that too… may I quote you on that?
<igli> sure, tho i doubt anyone will listen ;)
그러나 예외가있는 언어로 잘 사용하는 방법과 잘 사용하고 싶을 때의 제안은 다음과 같습니다.
초기 return의 대부분을 예외를 던지는 것으로 바꿀 수 있습니다 . 그러나 , 귀하의 일반적인 코드의 흐름 즉, 프로그램의 흐름이있는 프로그램은 물론, 예외 ... 오류 상태가 발생하거나 somesuch하지 않습니다 예외를 올립니다.
이것은…
# this page is only available to logged-in users
if not isLoggedIn():
# this is Python 2.5 style; insert your favourite raise/throw here
raise "eh?"
… 괜찮지 만…
/* do not code like this! */
try {
openFile(xyz, "rw");
} catch (LockedException e) {
return "file is locked";
}
closeFile(xyz);
return "file is not locked";
… 아니다. 기본적으로 예외는 제어 흐름 요소가 아닙니다 . 또한, "자바 프로그래머는 항상 이러한 예외가 정상이라고 알려주는"조작이 이상하게 보이고 디버깅을 방해 할 수 있습니다 (예 : IDE가 예외를 중단하도록 지시). 예외는 종종 스택 백을 해제하기 위해 스택을 풀기 위해 런타임 환경을 요구합니다. 이에 대한 더 많은 이유가있을 수 있습니다.
예외를 지원하는 언어에서는 기존 논리 및 스타일과 일치하고 자연스럽게 느껴지는 것을 사용하십시오. 처음부터 무언가를 작성하는 경우 조기에 동의하십시오. 라이브러리를 처음부터 작성하는 경우 소비자를 생각하십시오. ( abort()도서관 에서도 사용하지 마십시오 .) 그러나 무엇을하든 일반적으로 그 이후에 작업이 정상적으로 계속되는 경우 예외가 발생하지 않습니다.
전체 개발자 팀이 먼저 합의한 예외를 프로그램 내에서 모두 사용하도록하십시오. 기본적으로 계획하십시오. 그것들을 풍부하게 사용하지 마십시오. 때로는 C ++, Java ™, Python에서도 오류 리턴이 더 좋습니다. 때로는 그렇지 않습니다. 생각과 함께 사용하십시오.
goto fail;식별에 숨겨진 또 다른 것을 원하지 않습니다 .
(@mirabilos의 답변 은 훌륭하지만 다음은 동일한 결론에 도달하기 위해 질문에 대해 어떻게 생각하는지입니다.)
나는 나중에 내 기능 코드를 읽는 나 자신 (또는 다른 사람)에 대해 생각하고 있습니다. 첫 번째 줄을 읽으면 입력에 대해 어떤 가정도 할 수 없습니다 (어쨌든 확인하지 않는 것을 제외하고). 그래서 제 생각은 "좋아, 내가 논증으로 일을 할 것이라는 것을 알고 있지만, 먼저 정리해 보자"는 말이다. , 나는 정상적인 경우를 조절 된 것으로 보지 않는다; 나는 그것이 정상임을 강조하고 싶다.
int foo(int* bar, int baz) {
if (bar == NULL) /* I don't like you, leave me alone */;
if (baz < 0) /* go away */;
/* there, now I can do the work I came into this function to do,
and I can safely forget about those if's above and make all
the assumptions I like. */
/* etc. */
}
이러한 종류의 조건 순서는 해당 코드 섹션의 중요도 및 사용할 수있는 기본값이 있는지 여부에 따라 다릅니다.
다시 말해:
A. 중요 섹션 및 기본값 없음 => 조기 실패
B. 중요하지 않은 섹션 및 기본값 => 다른 부분 에서 기본값 사용
C. 사례 간 => 필요에 따라 사례별로 결정