함수에 하나의 return 문만있는 것이 더 좋은 이유는 무엇입니까?
또는 논리적으로 정확하자마자 함수에서 반환해도됩니다. 즉, 함수에 많은 return 문이있을 수 있습니까?
함수에 하나의 return 문만있는 것이 더 좋은 이유는 무엇입니까?
또는 논리적으로 정확하자마자 함수에서 반환해도됩니다. 즉, 함수에 많은 return 문이있을 수 있습니까?
답변:
나는 종종 "쉬운"상황으로 돌아 가기 위해 메소드를 시작할 때 몇 가지 진술을한다. 예를 들면 다음과 같습니다.
public void DoStuff(Foo foo)
{
if (foo != null)
{
...
}
}
... 다음과 같이 더 읽기 쉽게 (IMHO) 만들 수 있습니다.
public void DoStuff(Foo foo)
{
if (foo == null) return;
...
}
그렇습니다. 함수 / 메소드에서 여러 "종료점"을 갖는 것이 좋습니다.
DoStuff() { DoStuffInner(); IncreaseStuffCallCounter(); }
아무도 언급하거나 인용하지 않았습니다 Code Complete를 하지 않았으므로 그렇게 할 것입니다.
각 루틴의 수익 수를 최소화 . 맨 아래에서 루틴을 읽고 위의 어딘가에 리턴 될 가능성을 모르면 루틴을 이해하기가 더 어렵습니다.
가독성을 높이려면 리턴을 사용하십시오 . 특정 루틴에서 응답을 알고 나면 즉시 호출 루틴으로 리턴하려고합니다. 루틴이 정리가 필요없는 방식으로 정의 된 경우 즉시 리턴하지 않으면 더 많은 코드를 작성해야합니다.
기술이 실제로 반복 해서 유용하다는 것을 알았으므로 여러 종료점에 대해 임의로 결정하는 것은 엄청나게 현명하지 않을 것이라고 말할 것입니다 . 실제로 는 명확성을 위해 기존 코드 를 여러 개의 종료점으로 리팩토링했습니다 . 따라서 두 가지 접근법을 비교할 수 있습니다.
string fooBar(string s, int? i) {
string ret = "";
if(!string.IsNullOrEmpty(s) && i != null) {
var res = someFunction(s, i);
bool passed = true;
foreach(var r in res) {
if(!r.Passed) {
passed = false;
break;
}
}
if(passed) {
// Rest of code...
}
}
return ret;
}
여러 종료 지점 코드이 비교 된다 허용 : -
string fooBar(string s, int? i) {
var ret = "";
if(string.IsNullOrEmpty(s) || i == null) return null;
var res = someFunction(s, i);
foreach(var r in res) {
if(!r.Passed) return null;
}
// Rest of code...
return ret;
}
후자는 상당히 명확하다고 생각합니다. 내가 여러 출구 지점에 대한 비판을 말할 수있는 한 요즘은 다소 고전적인 관점입니다.
저는 현재 코드베이스에서 작업하는 두 사람이 "단일 종료점"이론을 맹목적으로 구독하는 코드베이스를 작업 중이며 경험을 통해 끔찍한 끔찍한 사례라고 말할 수 있습니다. 코드를 유지 관리하기가 매우 어려워서 그 이유를 보여 드리겠습니다.
"단일 종료점"이론을 사용하면 필연적으로 다음과 같은 코드가 생깁니다.
function()
{
HRESULT error = S_OK;
if(SUCCEEDED(Operation1()))
{
if(SUCCEEDED(Operation2()))
{
if(SUCCEEDED(Operation3()))
{
if(SUCCEEDED(Operation4()))
{
}
else
{
error = OPERATION4FAILED;
}
}
else
{
error = OPERATION3FAILED;
}
}
else
{
error = OPERATION2FAILED;
}
}
else
{
error = OPERATION1FAILED;
}
return error;
}
이렇게하면 코드를 따르기가 매우 어려울뿐만 아니라 나중에 다시 돌아가서 1과 2 사이의 작업을 추가해야한다고 말하십시오. 전체 괴물 기능에 대해 들여 쓰기해야하며 행운을 빌어야합니다. if / else 조건과 괄호가 올바르게 일치하는지 확인하십시오.
이 방법을 사용하면 코드 유지 관리가 매우 어렵고 오류가 발생하기 쉽습니다.
구조화 된 프로그래밍에 따르면 함수 당 하나의 return 문만 있어야합니다. 이것은 복잡성을 제한하기위한 것입니다. Martin Fowler와 같은 많은 사람들은 여러 개의 return 문으로 함수를 작성하는 것이 더 간단하다고 주장합니다. 그는 자신이 쓴 고전적인 리팩토링 책 에서이 주장을 제시한다 . 다른 조언을 따르고 작은 기능을 작성하면 잘 작동합니다. 나는이 관점에 동의하며 엄격한 구조적 프로그래밍 순수 주의자 만이 함수 당 단일 리턴 문을 준수합니다.
GOTO
기능이 존재하더라도 제어 흐름을 이동 하는 데 사용 하는 것에 대해 이야기 했습니다. "사용하지 마십시오 GOTO
" 라고 절대 말하지 않습니다 .
Kent Beck이 구현 패턴 에서 가드 절을 논의 할 때 루틴을 만드는 것은 단일 진입 점과 종료점을 갖습니다 ...
"동일한 루틴으로 여러 위치로 들어오고 나갈 때 혼동을 피할 수있었습니다. FORTRAN 또는 많은 글로벌 데이터로 작성된 어셈블리 언어 프로그램에 적용 할 때 어떤 명령문이 실행되었는지 이해하는 것이 어려운 경우에 적합했습니다. 작은 방법과 대부분의 로컬 데이터 만 있으면 불필요하게 보수적입니다. "
하나의 긴 중첩 if then else
문 보다 가드 절로 작성된 함수를 훨씬 쉽게 찾을 수 있습니다.
부작용이없는 함수에서는 단일 리턴 이상을 가질만한 이유가 없으며 기능적인 스타일로 작성해야합니다. 부작용이있는 방법에서는 상황이보다 순차적 (시간 색인화 됨)되므로 return 문을 명령으로 사용하여 명령을 실행 중지 명령으로 작성합니다.
즉, 가능하면이 스타일을 선호하십시오.
return a > 0 ?
positively(a):
negatively(a);
이 위에
if (a > 0)
return positively(a);
else
return negatively(a);
여러 계층의 중첩 조건을 작성하는 경우 술어 목록을 사용하여 리팩토링 할 수있는 방법이있을 수 있습니다. if와 else가 구문 적으로 멀리 떨어져 있음을 발견하면 더 작은 함수로 세분화 할 수 있습니다. 한 화면 이상의 텍스트에 걸쳐있는 조건부 블록은 읽기가 어렵습니다.
모든 언어에 적용되는 단단하고 빠른 규칙은 없습니다. 단일 return 문을 사용하는 것만으로는 코드가 좋지 않습니다. 그러나 좋은 코드는 그런 식으로 함수를 작성하는 경향이 있습니다.
RAII 또는 다른 자동 메모리 관리가없는 경우 각 반품마다 정리해야합니다. 정리 또는 goto (논리적으로 관리되는 언어에서 '최종'과 동일)의 둘 다 잘못된 형식으로 간주됩니다. C ++ 또는 다른 자동 메모리 시스템에서 스마트 포인터 및 컬렉션을 사용하는 경우에는 그럴만 한 이유가 없으며 가독성과 더 많은 판단이 필요합니다.
auto_ptr
경우 일반 포인터를 병렬로 사용할 수 있습니다. 처음에는 최적화되지 않은 컴파일러로 '최적화 된'코드를 작성하는 것이 이상 할 것입니다.
try
... finally
) 자원 유지 보수를 수행해야하는 경우 단일로 수행 할 수 있습니다. 메소드의 끝에서 리턴 이를 수행하기 전에 상황을 제거하기 위해 코드 리팩토링을 신중하게 고려해야합니다.
함수 중간 에 return 문 이 잘못 되었다는 생각 에 의존합니다. 리턴을 사용하여 함수 상단에 몇 가지 가드 절을 작성할 수 있으며 물론 컴파일러에게 문제없이 함수 끝에서 리턴 할 항목을 알려주지 만 함수 중간 에 리턴하는 것은 놓치기 쉬울 수 있습니다. 함수를 해석하기 어렵게 만듭니다.
함수에 하나의 return 문만있는 것이 더 좋은 이유는 무엇입니까?
예 , 있습니다 :
이 질문은 종종 여러 반환 또는 깊은 중첩 if 문 사이의 잘못된 이분법으로 제기됩니다. 거의 항상 하나의 출구 지점으로 매우 선형 (깊은 중첩 없음) 인 세 번째 솔루션이 있습니다.
업데이트 : 분명히 MISRA 지침은 단일 출구를 촉진합니다 합니다.
분명히하기 위해, 여러 번의 수익을 얻는 것이 항상 잘못되었다는 말은 아닙니다 . 그러나 동등한 솔루션이 주어지면 단일 수익을 가진 솔루션을 선호하는 데에는 많은 이유가 있습니다.
Contract.Ensures
하여 여러 리턴 포인트와 함께 사용할 수 있기 때문에 사후 조건 문제는 문제가되지 않습니다 .
goto
일반적인 정리 코드를 얻는 데 사용 하는 경우 정리 코드 return
끝에 하나가 있도록 함수를 단순화했을 것입니다 . 따라서 문제를 해결했다고 말할 수는 goto
있지만을 하나로 단순화하여 문제를 해결했다고 말할 수 있습니다 return
.
단일 종료점을 갖는 것은 함수의 끝에 단일 중단 점을 설정하여 실제로 리턴 될 값을 확인할 수 있기 때문에 디버깅에 유리합니다.
일반적으로 함수에서 하나의 종료점 만 갖려고합니다. 그러나 실제로 그렇게하면 필요한 것보다 더 복잡한 함수 본문이 만들어지는 경우가 있습니다.이 경우 여러 개의 종료점을 갖는 것이 좋습니다. 결과적으로 복잡성을 기반으로 한 "심사 요청"이어야하지만 목표는 복잡성과 이해도를 희생하지 않으면 서 가능한 적은 출구 지점이어야합니다.
아니요, 1970 년대에 더 이상 살지 않기 때문 입니다. 함수가 여러 리턴 값이 문제가 될만큼 충분히 길면 너무 깁니다.
(예외가있는 언어의 여러 줄 함수에는 여러 개의 종료 점이 있습니다.)
실제로 상황을 복잡하게하지 않는 한 단일 출구를 선호합니다. 경우에 따라 여러 개의 존재 지점이 다른 중요한 디자인 문제를 숨길 수 있음을 발견했습니다.
public void DoStuff(Foo foo)
{
if (foo == null) return;
}
이 코드를 보면 즉시 다음과 같이 묻습니다.
이러한 질문에 대한 답변에 따라
위의 두 경우 모두 'foo'가 null이 아니며 관련 호출자가 변경되도록하기 위해 어설 션으로 코드를 재 작업 할 수 있습니다.
여러 개가 존재하는 두 가지 다른 이유 (구체적으로 C ++ 코드로 생각)가 실제로 음수를 가질 수 있습니다 영향을 줄 수 있습니다. 그것들은 코드 크기와 컴파일러 최적화입니다.
함수 종료시 범위에있는 비 POD C ++ 객체에는 소멸자가 호출됩니다. 리턴 문이 여러 개인 경우 범위에 다른 오브젝트가있을 수 있으므로 호출 할 소멸자 목록이 달라집니다. 따라서 컴파일러는 각 return 문에 대한 코드를 생성해야합니다.
void foo (int i, int j) {
A a;
if (i > 0) {
B b;
return ; // Call dtor for 'b' followed by 'a'
}
if (i == j) {
C c;
B b;
return ; // Call dtor for 'b', 'c' and then 'a'
}
return 'a' // Call dtor for 'a'
}
코드 크기가 문제라면 피할 가치가 있습니다.
다른 문제는 "명명 된 반환 값 최적화"(일명 복사 제거, ISO C ++ '03 12.8 / 15)와 관련이 있습니다. C ++에서는 구현이 다음과 같은 경우 복사 생성자 호출을 건너 뛸 수 있습니다.
A foo () {
A a1;
// do something
return a1;
}
void bar () {
A a2 ( foo() );
}
코드를 그대로 사용하면 객체 'a1'은 'foo'로 구성되고 복사 구성은 'a2'를 구성하기 위해 호출됩니다. 그러나 복사 제거는 컴파일러가 스택에서 'a2'와 동일한 위치에 'a1'을 구성 할 수 있도록합니다. 따라서 함수가 반환 될 때 객체를 "복사"할 필요가 없습니다.
다중 종료점은이를 감지하는 데있어 컴파일러의 작업을 복잡하게 만들고, 상대적으로 최신 버전의 VC ++의 경우 함수 본문에 다중 리턴이있는 위치에서는 최적화가 수행되지 않았습니다. 자세한 내용 은 Visual C ++ 2005의 명명 된 반환 값 최적화 를 참조하십시오.
throw new ArgumentNullException()
이 경우 C #에서 와 같이 Assert 제안도 반환 지점입니다 ) 다른 고려 사항이 마음에 들었습니다. 모두 나에게 유효하며 일부에서는 중요 할 수 있습니다 틈새 컨텍스트.
foo
테스트되고 어떻게해야하는지 여부입니다 주제와는 아무 상관이 없습니다 if (foo == NULL) return; dowork;
또는if (foo != NULL) { dowork; }
종료 점이 하나 있으면 사이클로 매틱 복잡성이 감소 하므로 이론적 으로 코드를 변경할 때 버그가 발생할 가능성이 줄어 듭니다. 그러나 연습은보다 실용적인 접근 방식이 필요하다는 것을 암시하는 경향이 있습니다. 따라서 단일 종료점을 갖는 것을 목표로하지만 더 읽기 쉬운 코드는 여러 개 가질 수 있습니다.
return
어떤 의미에서는 코드 냄새가 나기 때문에 하나의 문장 만 사용하도록 강요 합니다. 설명하겠습니다 :
function isCorrect($param1, $param2, $param3) {
$toret = false;
if ($param1 != $param2) {
if ($param1 == ($param3 * 2)) {
if ($param2 == ($param3 / 3)) {
$toret = true;
} else {
$error = 'Error 3';
}
} else {
$error = 'Error 2';
}
} else {
$error = 'Error 1';
}
return $toret;
}
(조건은 영국식입니다 ...)
조건이 많을수록 함수가 커질수록 읽기가 더 어려워집니다. 따라서 코드 냄새에 익숙해지면이를 인식하고 코드를 리팩토링하려고합니다. 가능한 두 가지 솔루션은 다음과 같습니다.
여러 반환
function isCorrect($param1, $param2, $param3) {
if ($param1 == $param2) { $error = 'Error 1'; return false; }
if ($param1 != ($param3 * 2)) { $error = 'Error 2'; return false; }
if ($param2 != ($param3 / 3)) { $error = 'Error 3'; return false; }
return true;
}
별도의 기능
function isEqual($param1, $param2) {
return $param1 == $param2;
}
function isDouble($param1, $param2) {
return $param1 == ($param2 * 2);
}
function isThird($param1, $param2) {
return $param1 == ($param2 / 3);
}
function isCorrect($param1, $param2, $param3) {
return !isEqual($param1, $param2)
&& isDouble($param1, $param3)
&& isThird($param2, $param3);
}
물론 더 길고 약간 지저분하지만이 방법으로 함수를 리팩터링하는 과정에서
나는 C #으로 작성한 코드에서 일반적으로 여러 반환이 좋다고 생각합니다. 단일 반환 스타일은 C의 보류 방식이지만 C로 코딩되지 않았을 수 있습니다.
모든 프로그래밍 언어에서 메소드에 대해 하나의 종료점 만 요구하는 법은 없습니다 . 어떤 사람들은이 스타일의 우월성을 주장하고 때로는 "규칙"이나 "법"으로 높이려고하지만이 믿음은 어떠한 증거 나 연구에 의해서도 뒷받침되지 않습니다.
자원을 명시 적으로 할당 해제해야하는 C 코드에서는 하나 이상의 리턴 스타일이 나쁜 습관 일 수 있지만 Java, C #, Python 또는 JavaScript와 같은 언어는 자동 가비지 콜렉션 및 try..finally
블록 (및using
C #의 블록) . ),이 주장은 적용되지 않습니다. 이러한 언어에서는 중앙 집중식 수동 리소스 할당 해제가 필요합니다.
단일 수익률이 더 읽기 쉬운 경우와 그렇지 않은 경우가 있습니다. 코드 줄 수를 줄이거 나 논리를 더 명확하게 만들거나 중괄호와 들여 쓰기 또는 임시 변수 수를 줄이십시오.
따라서 기술적 인 문제가 아닌 레이아웃 및 가독성 문제이기 때문에 예술적 감각에 맞는만큼의 수익을 사용하십시오.
내 블로그에서 이것에 대해 더 오랫동안 이야기했습니다 .
필연적으로 발생하는 "화살표" 프로그래밍 에 대해 나쁜 말이있는 것처럼 단일 종료점을 갖는 것에 대해 좋은 말이 있습니다.
입력 유효성 검사 또는 리소스 할당 중에 여러 개의 종료점을 사용하는 경우 모든 '오류 종료'를 함수의 맨 위에 눈에 띄게 배치하려고합니다.
"SSDSLPedia" 의 스파르타 프로그래밍 기사와 단일 기능 종료점 "Portland Pattern Repository 's Wiki" 기사에는이 문제에 대한 통찰력있는 주장이 있습니다. 물론이 게시물도 고려해야합니다.
예를 들어, 한 곳에서 리소스를 해제하기 위해 예를 들어 비 사용 언어로 된 단일 종료점을 원한다면 goto를 신중하게 적용하는 것이 좋습니다. 예를 들어이 다소 고안된 예를 참조하십시오 (화면 부동산을 저장하기 위해 압축).
int f(int y) {
int value = -1;
void *data = NULL;
if (y < 0)
goto clean;
if ((data = malloc(123)) == NULL)
goto clean;
/* More code */
value = 1;
clean:
free(data);
return value;
}
개인적으로 나는 일반적으로 여러 종료점을 싫어하는 것보다 화살표 프로그래밍을 싫어하지만 둘 다 올바르게 적용하면 유용합니다. 물론 최선의 방법은 프로그램이 어느 것도 요구하지 않도록 구성하는 것입니다. 함수를 여러 청크로 나누면 일반적으로 도움이됩니다. :)
그렇게 할 때이 예제에서와 같이 어쨌든 여러 개의 종료 점이 발생합니다. 여기 더 큰 함수는 몇 개의 작은 함수로 나뉩니다.
int g(int y) {
value = 0;
if ((value = g0(y, value)) == -1)
return -1;
if ((value = g1(y, value)) == -1)
return -1;
return g2(y, value);
}
프로젝트 또는 코딩 지침에 따라 대부분의 보일러 플레이트 코드는 매크로로 대체 될 수 있습니다. 참고로, 이런 식으로 분류하면 g0, g1, g2 기능을 개별적으로 테스트하기가 매우 쉽습니다.
분명히, OO 및 예외 가능 언어에서 나는 그런 if 문을 사용하지 않을 것입니다 (또는 전혀 노력을 기울이지 않고도 해결할 수 있다면) 코드는 훨씬 더 명확합니다. 비 화살. 그리고 비 최종 수익은 대부분 예외 일 것입니다.
한마디로;
당신은 adage- beauty가 보는 사람의 눈에 있다는 것을 알고 있습니다.
일부 사람들은 NetBeans 와 일부는 IntelliJ IDEA , 일부는 Python , PHP는 맹세합니다 .
일부 상점에서는 다음과 같이 고집하면 직업을 잃을 수 있습니다.
public void hello()
{
if (....)
{
....
}
}
문제는 가시성과 유지 보수성에 관한 것입니다.
부울 대수를 사용하여 논리와 상태 머신의 사용을 줄이고 단순화하는 데 중독되어 있습니다. 그러나 코딩에서 "수학적 기술"을 사용하는 것이 적합하지 않다고 생각한 과거 동료들이있었습니다. 그리고 그것은 나쁜 습관이 될 것입니다. 죄송합니다. 제가 사용하는 기술은 매우 눈에 잘 띄고 유지 관리가 가능합니다. 6 개월 후 코드로 돌아 오면 코드가 오히려 스파게티의 혼란을 분명하게 이해하게 될 것이기 때문입니다.
이봐 친구 (이전의 고객과 마찬가지로)는 내가 그것을 고칠 필요가있을 때 고치는 방법을 아는 한 원하는 것을합니다.
20 년 전, 내 동료가 오늘날 민첩한 개발 전략 이라고 불리는 것을 사용하여 해고 된 것을 기억 합니다. 그는 세심한 점진적 계획을 세웠다. 그러나 그의 매니저 당신은 점진적으로 사용자에게 기능을 해제 할 수 있습니다 "그에게 고함했다! 당신은 고수해야한다 폭포 ." 관리자에 대한 그의 반응은 증분 개발이 고객의 요구에 더 정확할 것이라는 것이 었습니다. 그는 고객의 요구를 충족시키기 위해 노력했지만 관리자는 "고객의 요구 사항"에 따른 코딩을 믿었습니다.
데이터 정규화, MVP 및 MVC 경계 를 위반 한 경우가 종종 있습니다. 함수를 구성하는 대신 인라인합니다. 우리는 지름길을 취합니다.
개인적으로, 나는 PHP가 나쁜 습관이라고 생각하지만 무엇을 알고 있습니까? 모든 이론적 주장은 하나의 규칙 집합을 이행하려고 노력합니다.
품질 = 정밀성, 유지 보수성 및 수익성.
다른 모든 규칙은 배경으로 사라집니다. 물론이 규칙은 결코 사라지지 않습니다.
게으름은 훌륭한 프로그래머의 미덕입니다.
가드 절을 사용하여 일찍 반환하고 그렇지 않으면 메서드가 끝날 때 종료됩니다. 단일 입력 및 종료 규칙은 역사적으로 중요한 의미를 지니고 있으며 여러 개의 리턴 (및 많은 결함)이있는 단일 C ++ 메소드에 대해 10 A4 페이지로 실행되는 레거시 코드를 처리 할 때 특히 유용했습니다. 보다 최근에, 허용되는 모범 사례는 방법을 작게 유지하여 다중 출구가 이해에 대한 임피던스를 덜 만드는 것입니다. 위에서 복사 한 다음 Kronoz 예제에서 질문은 // Rest of code ... ? 에서 발생하는 것입니다 .
void string fooBar(string s, int? i) {
if(string.IsNullOrEmpty(s) || i == null) return null;
var res = someFunction(s, i);
foreach(var r in res) {
if(!r.Passed) return null;
}
// Rest of code...
return ret;
}
나는 예제가 다소 고안 되었다는 것을 알고 있지만 foreach 루프를 LINQ 문으로 리팩터링하여 유혹 조항으로 간주 할 수 있습니다. 다시 한 번, 고안된 예에서 코드의 의도는 명확하지 않으며 someFunction () 은 다른 부작용이 있거나 결과가 // Rest of code ... 에서 사용될 수 있습니다 .
if (string.IsNullOrEmpty(s) || i == null) return null;
if (someFunction(s, i).Any(r => !r.Passed)) return null;
다음과 같은 리팩토링 된 기능 제공 :
void string fooBar(string s, int? i) {
if (string.IsNullOrEmpty(s) || i == null) return null;
if (someFunction(s, i).Any(r => !r.Passed)) return null;
// Rest of code...
return ret;
}
null
인수가 받아 들여지지 않았다는 것을 나타내는 예외를 던지는 대신에 돌아가 겠습니까?
내가 생각할 수있는 한 가지 좋은 이유는 코드 유지 관리 때문입니다. 단일 종료 지점이 있습니다. 결과의 형식을 변경하려면 ..., 구현하는 것이 훨씬 간단합니다. 또한 디버깅을 위해 중단 점을 붙일 수 있습니다. :)
그러나 한 번 코딩 표준이 '함수 당 하나의 리턴 명령문'을 부과하는 라이브러리에서 작업해야했으며 꽤 힘들다는 것을 알았습니다. 나는 많은 숫자 계산 코드를 작성하고 종종 '특별한 경우'가 있으므로 코드를 따르기가 매우 어려워졌습니다 ...
나는 당신에게 단일 출구 경로를 강요하는 끔찍한 코딩 표준으로 작업했으며 그 기능이 사소한 것이 아니라면 결과는 거의 항상 구조화되지 않은 스파게티입니다. 많은 휴식으로 끝나고 계속 방해합니다.
if
각 메서드 호출이 반환 성공 여부 :( 앞에 문을
나의 일반적인 정책은 코드의 복잡성을 더 추가하여 코드의 복잡성을 크게 줄이지 않으면 함수 끝에 하나의 return 문 만 갖는 것입니다. 사실, 나는 에펠 탑의 팬인데 반환 진술을하지 않아도 유일한 반환 규칙을 시행합니다 (결과를 자동으로 생성하는 '결과'변수가 있습니다).
명백한 버전이없는 것보다 여러 번 리턴하여 코드를 명확하게 할 수있는 경우가 있습니다. 여러 개의 return 문없이 이해할 수없는 너무 복잡한 함수가있는 경우 더 많은 재 작업이 필요하다고 주장 할 수 있지만 때로는 그러한 것들에 대해 실용적이기는 좋습니다.
몇 번의 반환으로 끝나면 코드에 문제가있을 수 있습니다. 그렇지 않으면 때로는 코드를 더 깨끗하게 만들 때 서브 루틴의 여러 위치에서 돌아올 수 있다는 것이 때때로 동의 할 것입니다.
sub Int_to_String( Int i ){
given( i ){
when 0 { return "zero" }
when 1 { return "one" }
when 2 { return "two" }
when 3 { return "three" }
when 4 { return "four" }
...
default { return undef }
}
}
이처럼 더 잘 작성 될 것입니다
@Int_to_String = qw{
zero
one
two
three
four
...
}
sub Int_to_String( Int i ){
return undef if i < 0;
return undef unless i < @Int_to_String.length;
return @Int_to_String[i]
}
이것은 간단한 예일뿐입니다.
마지막에 단일 반환에 대한 지침으로 투표합니다. 이것은 일반적인 코드 정리 처리에 도움이됩니다 ... 예를 들어 다음 코드를 살펴보십시오 ...
void ProcessMyFile (char *szFileName)
{
FILE *fp = NULL;
char *pbyBuffer = NULL:
do {
fp = fopen (szFileName, "r");
if (NULL == fp) {
break;
}
pbyBuffer = malloc (__SOME__SIZE___);
if (NULL == pbyBuffer) {
break;
}
/*** Do some processing with file ***/
} while (0);
if (pbyBuffer) {
free (pbyBuffer);
}
if (fp) {
fclose (fp);
}
}
이것은 아마도 특이한 관점이지만, 여러 개의 return 문을 선호한다고 믿는 사람은 4 개의 하드웨어 중단 점 만 지원하는 마이크로 프로세서에서 디버거를 사용할 필요가 없다고 생각합니다. ;-)
"화살표 코드"문제는 완전히 정확하지만 여러 return 문을 사용할 때 사라지는 문제는 디버거를 사용하는 상황에 있습니다. 출구를보고 복귀 조건을 볼 수 있도록 중단 점을 놓을 편리한 포괄 위치는 없습니다.