문제

함수에 하나의 return 문만 갖는 것이 더 나은 방법인 타당한 이유가 있습니까?

아니면 논리적으로 올바른 경우(즉, 함수에 많은 return 문이 있을 수 있음을 의미) 함수에서 반환해도 괜찮습니까?

도움이 되었습니까?

해결책

나는 종종 "쉬운" 상황에 대해 반환하기 위해 메서드 시작 부분에 여러 가지 명령문을 사용합니다.예를 들면 다음과 같습니다.

public void DoStuff(Foo foo)
{
    if (foo != null)
    {
        ...
    }
}

...다음과 같이 더 읽기 쉽게 만들 수 있습니다(IMHO).

public void DoStuff(Foo foo)
{
    if (foo == null) return;

    ...
}

그렇습니다. 함수/메서드에서 여러 개의 "종료 지점"을 갖는 것이 좋다고 생각합니다.

다른 팁

아무도 언급하거나 인용하지 않았습니다. 코드 완성 그래서 내가 할게.

17.1 반품

각 루틴의 반환 횟수를 최소화하세요..루틴을 맨 아래에서 읽을 때 위 어딘가에서 반환될 가능성을 인식하지 못한다면 루틴을 이해하기가 더 어렵습니다.

사용 반품 가독성을 높일 때.특정 루틴에서는 답을 알고 나면 즉시 호출 루틴으로 반환하려고 합니다.루틴이 정리가 필요하지 않은 방식으로 정의된 경우 즉시 반환하지 않으면 더 많은 코드를 작성해야 함을 의미합니다.

나는 이 기술이 실제로 유용하다는 것을 알았기 때문에 여러 출구 지점에 대해 임의로 결정하는 것은 믿을 수 없을 정도로 현명하지 못할 것이라고 말하고 싶습니다. 다시 반복하여, 사실 저는 자주 그랬어요 기존 코드를 리팩토링했습니다. 명확성을 위해 여러 출구 지점으로 이동합니다.따라서 두 가지 접근 방식을 비교할 수 있습니다.

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 문을 사용하여 함수를 작성하는 것이 더 간단하다고 주장합니다.그는 고전에서 이 주장을 제시한다. 리팩토링 그가 쓴 책.그의 다른 조언을 따르고 작은 함수를 작성하면 잘 작동합니다.나는 이 관점에 동의하며 엄격한 구조적 프로그래밍 순수주의자만이 함수당 단일 반환 문을 고수합니다.

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 문을 갖는 것과 같은 것만으로는 코드가 좋아지지 않습니다.그러나 좋은 코드를 사용하면 함수를 그런 식으로 작성할 수 있습니다.

나는 C의 숙취인 C++ 코딩 표준에서 그것을 보았습니다. 마치 RAII나 다른 자동 메모리 관리가 없는 것처럼 반환할 때마다 정리해야 합니다. 이는 잘라내어 붙여넣기를 의미합니다. 정리 또는 goto(관리 언어의 '최종'과 논리적으로 동일) 둘 다 잘못된 형식으로 간주됩니다.귀하의 관행이 C++ 또는 다른 자동 메모리 시스템에서 스마트 포인터 및 컬렉션을 사용하는 것이라면 이에 대한 강력한 이유가 없으며 가독성에 관한 것이며 더 많은 판단 요구가 됩니다.

나는 가운데 기능이 나쁩니다.return을 사용하여 함수 상단에 몇 가지 보호 절을 작성할 수 있으며 물론 문제 없이 함수 끝에서 무엇을 반환할지 컴파일러에 알려줄 수 있습니다. 가운데 함수의 내용은 놓치기 쉽고 함수를 해석하기 어렵게 만들 수 있습니다.

함수에 하나의 return 문만 갖는 것이 더 나은 방법인 타당한 이유가 있습니까?

, 다음이 있습니다:

  • 단일 종료 지점은 사후 조건을 주장할 수 있는 훌륭한 장소를 제공합니다.
  • 함수 끝의 하나의 반환에 디버거 중단점을 설정할 수 있으면 유용한 경우가 많습니다.
  • 반품이 적다는 것은 복잡성이 줄어든다는 것을 의미합니다.선형 코드는 일반적으로 이해하기가 더 쉽습니다.
  • 함수를 단일 반환으로 단순화하려고 하면 복잡성이 발생하는 경우 더 작고, 더 일반적이며, 이해하기 쉬운 함수로 리팩토링하는 것이 좋습니다.
  • 소멸자가 없는 언어를 사용하거나 RAII를 사용하지 않는 경우 단일 반환으로 정리해야 하는 장소 수가 줄어듭니다.
  • 일부 언어에는 단일 종료 지점이 필요합니다(예: Pascal 및 에펠).

이 질문은 종종 여러 반환 또는 깊게 중첩된 if 문 사이의 잘못된 이분법으로 제기됩니다.거의 항상 단일 종료점만 있는 매우 선형적인(깊은 중첩 없음) 세 번째 솔루션이 있습니다.

업데이트:보기에 MISRA 지침은 단일 종료를 장려합니다., 도.

분명히 말씀드리자면, 그렇다고 말하는 것이 아닙니다. 언제나 여러 반품이 있는 것은 잘못되었습니다.그러나 동등한 솔루션이 주어지면 단일 수익을 제공하는 솔루션을 선호하는 데에는 많은 이유가 있습니다.

단일 종료 지점을 사용하면 함수 끝에 단일 중단점을 설정하여 실제로 반환될 값을 확인할 수 있으므로 디버깅에 이점이 있습니다.

일반적으로 나는 함수의 종료 지점을 하나만 가지려고 합니다.그러나 이렇게 하면 실제로 필요한 것보다 더 복잡한 함수 본문이 생성되는 경우가 있습니다. 이 경우 여러 종료 지점을 갖는 것이 더 좋습니다.실제로 결과적인 복잡성을 기반으로 한 "판단 호출"이어야 하지만 목표는 복잡성과 이해 가능성을 희생하지 않고 가능한 한 적은 수의 종료 지점이어야 합니다.

아니, 왜냐면 우리는 더 이상 1970년대에 살고 있지 않습니다.함수가 여러 반환이 문제가 될 만큼 길다면 너무 긴 것입니다.

(예외가 있는 언어의 여러 줄 함수에는 어쨌든 여러 개의 종료 지점이 있다는 사실과는 별개입니다.)

상황이 정말 복잡해지지 않는 한 저는 단일 출구를 선호합니다.어떤 경우에는 여러 개의 존재 포인트가 다른 더 중요한 디자인 문제를 가릴 수 있다는 것을 발견했습니다.

public void DoStuff(Foo foo)
{
    if (foo == null) return;
}

이 코드를 보자마자 나는 즉시 이렇게 묻습니다.

  • 'foo'가 null인 경우가 있나요?
  • 그렇다면 'DoStuff'의 클라이언트 중 null 'foo'를 사용하여 함수를 호출한 적이 있는 클라이언트는 몇 개입니까?

이러한 질문에 대한 답변에 따라 다음과 같이 될 수 있습니다.

  1. 수표는 결코 사실이 아니므로 의미가 없습니다(예:주장이어야 합니다)
  2. 검사는 거의 사실이 아니며 어쨌든 다른 조치를 취해야 하므로 특정 호출자 기능을 변경하는 것이 더 나을 수 있습니다.

위의 두 경우 모두 'foo'가 결코 null이 아니며 관련 호출자가 변경되었는지 확인하기 위해 코드를 어설션으로 재작업할 수 있습니다.

다중 존재가 실제로 부정적인 영향을 미치다.코드 크기와 컴파일러 최적화입니다.

함수 종료 시 범위에 있는 POD가 아닌 C++ 개체의 소멸자는 호출됩니다.여러 개의 return 문이 있는 경우 범위에 다른 개체가 있을 수 있으므로 호출할 소멸자 목록이 다를 수 있습니다.따라서 컴파일러는 각 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'
}

코드 크기가 문제라면 피하는 것이 좋습니다.

다른 문제는 "명명된 반환 값 최적화"(일명 Copy Elision, 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의 명명된 반환 값 최적화 상세 사항은.

단일 출구 지점을 갖는 것은 감소합니다. 순환적 복잡성 따라서, 이론에 의하면, 코드를 변경할 때 코드에 버그가 발생할 확률이 줄어듭니다.그러나 실제로는 좀 더 실용적인 접근 방식이 필요하다고 제안하는 경향이 있습니다.따라서 나는 단일 종료 지점을 갖는 것을 목표로 하는 경향이 있지만, 더 읽기 쉬운 경우 코드에 여러 개를 갖도록 허용합니다.

억지로 하나만 사용하려고요 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 블록), 이 인수는 적용되지 않습니다. 이러한 언어에서는 중앙 집중식 수동 리소스 할당 해제가 필요한 경우가 매우 드뭅니다.

단일 반환이 더 읽기 쉬운 경우도 있고 그렇지 않은 경우도 있습니다.코드 줄 수를 줄이는지, 논리를 더 명확하게 만드는지, 중괄호와 들여쓰기 또는 임시 변수의 수를 줄이는지 확인하세요.

따라서 기술적인 문제가 아니라 레이아웃과 가독성 문제이기 때문에 예술적 감성에 맞는 만큼 많은 반환을 사용하십시오.

나는 다음과 같이 이야기했다. 이 내용은 내 블로그에 더 자세히 나와 있습니다..

피할 수 없는 일에 대해 나쁜 말이 있는 것처럼 단일 출구 지점을 갖는 것에 대해 좋은 말도 있습니다. "화살" 그 결과를 프로그래밍합니다.

입력 유효성 검사 또는 리소스 할당 중에 여러 종료 지점을 사용하는 경우 모든 '오류 종료'를 함수 상단에 눈에 띄게 배치하려고 합니다.

둘 다 스파르탄 프로그래밍 "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 문을 사용하지 않을 것이며(또는 최소한의 노력으로 해결할 수 있다면 전혀) 코드가 훨씬 더 단순해질 것입니다.그리고 화살이 아닙니다.그리고 최종이 아닌 수익의 대부분은 아마도 예외일 것입니다.

간단히 말해서;

  • 많은 수익보다 적은 수익이 더 좋습니다
  • 여러 번 돌아오는 것이 큰 화살보다 낫습니다. 가드 조항 일반적으로 괜찮습니다.
  • 가능한 경우 예외는 대부분의 '보호 조항'을 대체할 수 있거나 대체해야 합니다.

당신은 속담을 알고 있습니다 - 아름다움은 보는 사람의 눈에 달려 있다.

어떤 사람들은 맹세합니다. 넷빈즈 그리고 일부는 IntelliJ 아이디어, 일부 파이썬 그리고 일부는 PHP.

일부 상점에서는 다음과 같이 고집하면 직장을 잃을 수도 있습니다.

public void hello()
{
   if (....)
   {
      ....
   }
}

문제는 가시성과 유지 관리 가능성에 관한 것입니다.

나는 논리와 상태 기계의 사용을 줄이고 단순화하기 위해 부울 대수학을 사용하는 데 중독되어 있습니다.그러나 내가 코딩에 "수학적 기법"을 사용하는 것은 눈에 보이지도 않고 유지 관리도 불가능하기 때문에 부적합하다고 생각한 과거 동료들이 있었습니다.그리고 그것은 나쁜 습관이 될 것입니다.죄송합니다. 제가 사용하는 기술은 저에게 매우 눈에 띄고 유지 관리가 용이합니다. 왜냐하면 6개월 후 코드로 돌아오면 속담의 스파게티를 보는 것보다 코드를 명확하게 이해할 것이기 때문입니다.

안녕 친구(이전 고객이 말하곤 했던 것처럼) 내가 고쳐야 할 때 고치는 방법을 아는 한 원하는 대로 하세요.

나는 20년 전에 오늘날의 직업을 고용했다는 이유로 해고된 동료를 기억합니다. 민첩한 개발 전략.그는 세심한 증분 계획을 가지고 있었습니다.하지만 그의 관리자는 그에게 "사용자에게 기능을 점진적으로 출시할 수는 없습니다!"라고 소리쳤습니다.당신은 폭포." 관리자에 대한 그의 반응은 점진적인 개발이 고객의 요구에 더 정확할 것이라는 것이었습니다.그는 고객의 요구에 맞춰 개발해야 한다고 믿었지만 관리자는 "고객의 요구 사항"에 맞게 코딩해야 한다고 믿었습니다.

우리는 데이터 정규화를 위반하는 경우가 많습니다. MVP 그리고 MVC 경계.함수를 구성하는 대신 인라인합니다.우리는 지름길을 택합니다.

개인적으로 나는 PHP가 나쁜 습관이라고 생각하지만, 내가 아는 것은 무엇입니까?모든 이론적 주장은 한 세트의 규칙을 충족하려는 시도로 귀결됩니다.

품질 = 정밀도, 유지 관리 및 수익성.

다른 모든 규칙은 배경으로 사라집니다.물론 이 규칙은 결코 사라지지 않습니다.

게으름은 좋은 프로그래머의 미덕입니다.

나는 가드 절을 사용하여 일찍 반환하고 그렇지 않으면 메서드가 끝날 때 종료하는 경향이 있습니다.단일 시작 및 종료 규칙은 역사적 중요성을 가지며 다중 반환(및 많은 결함)이 있는 단일 C++ 메서드에 대해 10 A4 페이지에 실행되는 레거시 코드를 처리할 때 특히 유용했습니다.최근에는 여러 출구를 이해하는 데 방해가 되지 않도록 방법을 작게 유지하는 것이 허용되는 모범 사례입니다.위에서 복사한 다음 Kronoz 예에서 질문은 다음에서 발생합니다. //나머지 코드...?:

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;
}

나는 이 예가 다소 부자연스럽다는 것을 알고 있지만 각각 보호 절로 간주될 수 있는 LINQ 문을 반복합니다.다시 말하지만, 인위적인 예에서는 코드의 의도가 명확하지 않으며 일부함수() 다른 부작용이 있을 수도 있고 그 결과가 다음 용도로 사용될 수도 있습니다. // 나머지 코드....

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;
}

제가 생각할 수 있는 좋은 이유 중 하나는 코드 유지 관리입니다.단일 출구 지점이 있습니다.결과 형식을 변경하려는 경우... 구현하는 것이 훨씬 간단합니다.또한 디버깅을 위해 거기에 중단점을 추가할 수도 있습니다. :)

그렇긴 하지만, 나는 한때 코딩 표준이 '함수당 하나의 반환 문'을 요구하는 라이브러리에서 작업해야 했는데, 그것이 꽤 힘들었다는 것을 알았습니다.수치계산 코드를 많이 작성하다 보니 '특수한 경우'가 자주 발생해서 코드를 따라가기가 꽤 힘들더군요...

충분히 작은 기능, 즉 한 화면 길이에서 전체를 볼 수 있는 기능에는 여러 개의 종료 지점이 적합합니다.마찬가지로 긴 함수에 여러 종료 지점이 포함되어 있다면 이는 함수가 더 잘릴 수 있다는 신호입니다.

다중 종료 기능은 피한다고 하더군요 꼭 필요한 경우가 아니면.나는 더 복잡한 기능에서 일부 모호한 라인의 일부 잘못된 반환으로 인해 발생하는 버그로 인해 고통을 느꼈습니다.

나는 단일 종료 경로를 강제하는 끔찍한 코딩 표준을 사용하여 작업했으며 결과는 기능이 사소하지 않은 경우 거의 항상 구조화되지 않은 스파게티입니다. 결국 방해가 되는 많은 중단과 계속이 발생합니다.

단일 종료 지점 - 다른 모든 조건이 동일하므로 코드를 훨씬 더 읽기 쉽게 만듭니다.하지만 문제가 있습니다.대중적인 건축

resulttype res;
if if if...
return res;

가짜입니다. "res="는 "return"보다 별로 낫지 않습니다.단일 return 문이 있지만 함수가 실제로 끝나는 지점이 여러 개 있습니다.

여러 개의 반환값(또는 "res="s)이 있는 함수가 있는 경우 단일 종료 지점을 사용하여 여러 개의 작은 함수로 나누는 것이 좋습니다.

나의 일반적인 정책은 더 많은 것을 추가하여 코드의 복잡성이 크게 줄어들지 않는 한 함수 끝에 하나의 반환 문만 두는 것입니다.사실, 나는 return 문을 사용하지 않음으로써 유일한 반환 규칙을 시행하는 에펠의 팬입니다(결과를 넣을 자동 생성된 '결과' 변수만 있습니다).

다중 반환을 사용하면 코드가 없는 명백한 버전보다 코드가 더 명확해질 수 있는 경우가 확실히 있습니다.함수가 너무 복잡하여 여러 개의 return 문 없이는 이해할 수 없는 경우 더 많은 재작업이 필요하다고 주장할 수도 있지만 때로는 그러한 사항에 대해 실용적으로 생각하는 것이 좋습니다.

결과적으로 몇 번 이상의 반환이 발생하면 코드에 문제가 있을 수 있습니다.그렇지 않으면 특히 코드를 더 깔끔하게 만들 때 서브루틴의 여러 위치에서 돌아올 수 있는 것이 좋을 때가 있다는 데 동의합니다.

펄 6:나쁜 예

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 }
  }
}

이렇게 쓰는 게 낫겠다

펄 6:좋은 예

@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);
   }
}

이것은 아마도 특이한 관점일 것입니다. 그러나 다중 반환 문이 선호된다고 믿는 사람은 하드웨어 중단점을 4개만 지원하는 마이크로프로세서에서 디버거를 사용할 필요가 전혀 없다고 생각합니다.;-)

"화살표 코드" 문제는 완전히 정확하지만, 여러 개의 return 문을 사용할 때 사라지는 것처럼 보이는 문제 중 하나는 디버거를 사용하는 상황입니다.종료 및 그에 따른 반환 조건을 확인하기 위해 중단점을 설정할 수 있는 편리한 포괄 위치가 없습니다.

함수에 return 문이 많을수록 해당 메서드의 복잡성이 높아집니다.반환 문이 너무 많은지 궁금하다면 해당 함수에 코드 줄이 너무 많은지 자문해 보세요.

그러나 하나/다수의 return 문에는 아무런 문제가 없습니다.일부 언어에서는 다른 언어(C)보다 더 나은 방법(C++)입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top