Frage Sollte eine Funktion nur eine Return-Anweisung haben?


Gibt es gute Gründe, warum es besser ist, nur eine Return-Anweisung in einer Funktion zu haben?

Oder ist es in Ordnung, von einer Funktion zurückzukommen, sobald es logisch korrekt ist, was bedeutet, dass es viele Rückgabeanweisungen in der Funktion geben kann?


781


Ursprung


Antworten:


Ich habe oft mehrere Aussagen am Anfang einer Methode, um für "einfache" Situationen zurückzukehren. Zum Beispiel:

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

... kann so lesbarer gemacht werden (IMHO):

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

    ...
}

Also ja, ich denke, es ist in Ordnung, mehrere "Ausgangspunkte" von einer Funktion / Methode zu haben.


743



Niemand hat erwähnt oder zitiert Code abgeschlossen also werde ich es tun.

17.1 zurück

Minimiere die Anzahl der Rückgaben in jeder Routine. Es ist schwieriger, eine Routine zu verstehen, wenn man sie unten liest und nicht weiß, dass sie irgendwo zurückkommt.

Benutze einen Rückkehr wenn es die Lesbarkeit verbessert. Wenn Sie die Antwort in bestimmten Routinen kennen, möchten Sie sie sofort in die aufrufende Routine zurückgeben. Wenn die Routine so definiert ist, dass keine Bereinigung erforderlich ist, bedeutet die sofortige Rückgabe nicht, dass Sie mehr Code schreiben müssen.


355



Ich würde sagen, es wäre unglaublich unklug, willkürlich gegen mehrere Ausstiegspunkte zu entscheiden, da ich festgestellt habe, dass die Technik in der Praxis nützlich ist wieder und wiederTatsächlich habe ich oft bestehenden Code neu strukturiert zu mehreren Ausgangspunkten für Klarheit. Wir können die beiden Ansätze so vergleichen:

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

Vergleichen Sie dies mit dem Code, der mehrere Exit-Punkte enthält sind zulässig:-

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

Ich denke, Letzteres ist deutlich klarer. Soweit ich das beurteilen kann, ist die Kritik an mehreren Ausstiegspunkten heutzutage eine eher archaische Sichtweise.


229



Ich arbeite gerade an einer Codebasis, wo zwei der Leute, die daran arbeiten, blindlings die "Single Point of Exit" -Theorie akzeptieren und ich kann Ihnen sagen, dass es aus Erfahrung eine schreckliche, schreckliche Praxis ist. Es macht Code extrem schwierig zu pflegen und ich werde Ihnen zeigen, warum.

Mit der "Single-Point-of-Exit" -Theorie werden Sie unweigerlich mit Code konfrontiert, der so aussieht:

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

Dies macht nicht nur den Code sehr schwer zu befolgen, sondern Sie müssen später zurückgehen und eine Operation zwischen 1 und 2 hinzufügen. Sie müssen fast die gesamte Freaking-Funktion einrücken, und viel Glück, um alles zu tun Ihre if / else-Bedingungen und geschweiften Klammern werden korrekt abgeglichen.

Diese Methode macht die Codepflege extrem schwierig und fehleranfällig.


191



Strukturierte Programmierung sagt, man sollte immer nur eine Return-Anweisung pro Funktion haben. Dies soll die Komplexität begrenzen. Viele Leute wie Martin Fowler argumentieren, dass es einfacher ist, Funktionen mit mehreren Return-Anweisungen zu schreiben. Er präsentiert dieses Argument im Klassiker Refactoring Buch schrieb er. Das funktioniert gut, wenn Sie seinem anderen Rat folgen und kleine Funktionen schreiben. Ich stimme dieser Sichtweise zu und nur strikte strukturierte Programmpuristen halten sich an einzelne Return Statements pro Funktion.


72



Wie Kent Beck bei der Diskussion von Wächterklauseln in Implementierungsmuster Machen Sie eine Routine haben einen einzigen Ein- und Ausstiegspunkt ...

"war, um die Verwirrung zu verhindern   beim Springen in und aus vielen   Orte in der gleichen Routine. Es machte   gutes Gefühl, wenn auf FORTRAN oder angewendet   Assemblerprogramme geschrieben   mit vielen globalen Daten, wo sogar   zu verstehen, welche Aussagen waren   ausgeführt wurde harte Arbeit ... mit kleinen Methoden und meist lokalen Daten ist es unnötig konservativ. "

Ich finde eine Funktion, die mit Schutzklauseln geschrieben ist, viel einfacher zu folgen als eine lange verschachtelte Menge if then else Aussagen.


62



In einer Funktion, die keine Nebenwirkungen hat, gibt es keinen Grund, mehr als eine einzige Rückkehr zu haben, und Sie sollten sie in einem funktionalen Stil schreiben. In einer Methode mit Nebeneffekten sind die Dinge sequenzieller (Zeitindex), sodass Sie in einem imperativen Stil schreiben und die return-Anweisung als Befehl verwenden, um die Ausführung zu stoppen.

Mit anderen Worten, wenn möglich, bevorzugen Sie diesen Stil

return a > 0 ?
  positively(a):
  negatively(a);

darüber hinaus

if (a > 0)
  return positively(a);
else
  return negatively(a);

Wenn Sie feststellen, dass Sie mehrere Schichten geschachtelter Bedingungen schreiben, gibt es wahrscheinlich eine Möglichkeit, die Sie mithilfe der Prädikatliste umgestalten können. Wenn Sie feststellen, dass Ihre ifs und elns syntaktisch weit voneinander entfernt sind, möchten Sie das vielleicht in kleinere Funktionen aufteilen. Ein bedingter Block, der mehr als einen Bildschirm Text umfasst, ist schwer zu lesen.

Es gibt keine feste Regel, die für jede Sprache gilt. Etwas wie eine einzelne Return-Anweisung zu haben, wird Ihren Code nicht gut machen. Aber guter Code wird Ihnen erlauben, Ihre Funktionen so zu schreiben.


61



Ich habe es in Codierungsstandards für C ++ gesehen, die ein Hang-over von C waren, als ob Sie nicht RAII oder andere automatische Speicherverwaltung haben, dann müssen Sie für jede Rückkehr aufräumen, was entweder Ausschneiden und Einfügen bedeutet von der Aufräumaktion oder einem Goto (logisch das gleiche wie "endlich" in verwalteten Sprachen), die beide als schlechte Form angesehen werden. Wenn Ihre Praktiken in C ++ oder einem anderen automatischen Speichersystem intelligente Zeiger und Auflistungen verwenden sollen, dann gibt es keinen starken Grund dafür, und es geht nur um Lesbarkeit und mehr um einen Urteilsspruch.


43



Ich lehne die Idee ab, dass Aussagen in der Mitte der Funktion sind schlecht. Sie können Returns verwenden, um einige Guard-Klauseln am Anfang der Funktion zu erstellen, und natürlich dem Compiler mitteilen, was am Ende der Funktion ohne Probleme zurückgegeben werden soll Mitte der Funktion kann leicht übersehen werden und kann die Funktion schwieriger zu interpretieren machen.


40



Gibt es gute Gründe, warum es besser ist, nur eine Return-Anweisung in einer Funktion zu haben?

Ja, es gibt:

  • Der einzelne Ausstiegspunkt bietet einen ausgezeichneten Ort, um Ihre Nachbedingungen geltend zu machen.
  • Es ist oft nützlich, einen Debugger-Haltepunkt auf den einen Rückgabewert am Ende der Funktion zu setzen.
  • Weniger Rückmeldungen bedeuten weniger Komplexität. Linearer Code ist in der Regel einfacher zu verstehen.
  • Wenn der Versuch, eine Funktion zu einer einzigen Rückgabe zu vereinfachen, Komplexität verursacht, dann ist das ein Anreiz, zu kleineren, allgemeineren und leichter zu verstehenden Funktionen umzuformen.
  • Wenn Sie in einer Sprache ohne Destruktoren arbeiten oder wenn Sie RAII nicht verwenden, reduziert eine einzelne Rückgabe die Anzahl der Stellen, die Sie bereinigen müssen.
  • Einige Sprachen erfordern einen einzelnen Austrittspunkt (z. B. Pascal und Eiffel).

Die Frage wird oft als falsche Dichotomie zwischen Mehrfachrenditen oder tief verschachtelten if-Anweisungen gestellt. Es gibt fast immer eine dritte Lösung, die sehr linear ist (keine tiefe Verschachtelung) mit nur einem einzigen Austrittspunkt.

Aktualisieren: Anscheinend MISRA-Richtlinien fördern den Single-Exit, auch.

Um es klar zu sagen, ich sage es nicht immer falsch, mehrere Rückgaben zu haben. Bei ansonsten gleichwertigen Lösungen gibt es jedoch viele gute Gründe, den einen mit einer einzigen Rendite zu bevorzugen.


38



Das Vorhandensein eines einzelnen Exitpunkts bietet einen Vorteil beim Debuggen, da Sie damit am Ende einer Funktion einen einzelnen Breakpoint setzen können, um zu sehen, welcher Wert tatsächlich zurückgegeben wird.


33