779 Stimmen

Sollte eine Funktion nur eine Rückgabeanweisung haben?

Gibt es gute Gründe, warum es besser ist, nur eine Rückgabeanweisung in einer Funktion zu haben?

Oder ist es in Ordnung, aus einer Funktion zurückzukehren, sobald dies logisch korrekt ist, d.h. es kann viele Return-Anweisungen in der Funktion geben?

25 Stimmen

Ich stimme nicht zu, dass die Frage sprachenfeindlich ist. Bei einigen Sprachen ist die Mehrfachrückgabe natürlicher und bequemer als bei anderen. Ich würde mich eher über frühe Rückgaben in einer C-Funktion beschweren als in einer C++-Funktion, die RAII verwendet.

3 Stimmen

Diese Frage ist eng damit verbunden und enthält ausgezeichnete Antworten: programmers.stackexchange.com/questions/118703/

0 Stimmen

Sprachunabhängig? Erklären Sie jemandem, der eine funktionale Sprache verwendet, dass er einen Return pro Funktion verwenden muss :p

2voto

rrichter Punkte 8483

Sie haben bereits implizit mehrere implizite Rückgabeanweisungen, die durch die Fehlerbehandlung verursacht werden, also kommen Sie damit klar.

Wie bei der Programmierung üblich, gibt es jedoch sowohl Beispiele für als auch gegen die Praxis der Mehrfachrückgabe. Wenn es den Code übersichtlicher macht, sollte man es so oder so machen. Die Verwendung von vielen Kontrollstrukturen kann helfen (die Fall Anweisung, zum Beispiel).

1voto

starblue Punkte 53167

Ich bevorzuge eine einzelne Return-Anweisung. Ein Grund, auf den noch nicht hingewiesen wurde, ist, dass einige Refactoring-Tools besser für einzelne Ausgangspunkte funktionieren, z. B. Eclipse JDT extract/inline method.

1voto

Daniel Earwicker Punkte 111630

Im Interesse der gute Standards y beste Praktiken der Industrie müssen wir die korrekte Anzahl der Return-Anweisungen in allen Funktionen festlegen. Offensichtlich gibt es einen Konsens gegen eine einzige Return-Anweisung. Ich schlage daher vor, dass wir zwei festlegen.

Ich würde es begrüßen, wenn jeder jetzt seinen Code durchsehen und alle Funktionen mit nur einem Exit-Punkt ausfindig machen würde, um einen weiteren hinzuzufügen. Es spielt keine Rolle, wo.

Das Ergebnis dieses Wandels werden zweifellos weniger Fehler, eine bessere Lesbarkeit und ein unvorstellbarer Reichtum sein, der uns vom Himmel auf den Kopf fällt.

0 Stimmen

Ich habe versucht, witzig zu sein, aber es hat sich einfach bitter angehört, ich weiß!

1voto

Es gibt Zeiten, in denen dies aus Leistungsgründen notwendig ist (ich möchte nicht eine andere Cache-Zeile holen, wenn ich dasselbe Bedürfnis wie eine Fortsetzung habe; manchmal).

Wenn Sie Ressourcen (Speicher, Dateideskriptoren, Sperren usw.) zuweisen, ohne RAII zu verwenden, können mehrfache Rückgaben fehleranfällig sein und sind mit Sicherheit doppelt, da die Freigaben mehrfach manuell erfolgen müssen und Sie den Überblick behalten müssen.

In diesem Beispiel:

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

Ich hätte es so geschrieben:

function() {
    HRESULT error = OPERATION1FAILED;//assume failure
    if(SUCCEEDED(Operation1())) {

        error = OPERATION2FAILED;//assume failure
        if(SUCCEEDED(Operation3())) {

            error = OPERATION3FAILED;//assume failure
            if(SUCCEEDED(Operation3())) {

                error = OPERATION4FAILED; //assume failure
                if(SUCCEEDED(Operation4())) {

                    error = S_OK;
                }
            }
        }
    }
    return error;
}

Das scheint auf jeden Fall besser zu sein.

Dies ist besonders hilfreich, wenn es um die manuelle Freigabe von Ressourcen geht, da die Frage, wo und welche Freigaben erforderlich sind, ziemlich einfach zu beantworten ist. Wie im folgenden Beispiel:

function() {
    HRESULT error = OPERATION1FAILED;//assume failure
    if(SUCCEEDED(Operation1())) {

        //allocate resource for op2;
        char* const p2 = new char[1024];
        error = OPERATION2FAILED;//assume failure
        if(SUCCEEDED(Operation2(p2))) {

            //allocate resource for op3;
            char* const p3 = new char[1024];
            error = OPERATION3FAILED;//assume failure
            if(SUCCEEDED(Operation3(p3))) {

                error = OPERATION4FAILED; //assume failure
                if(SUCCEEDED(Operation4(p2,p3))) {

                    error = S_OK;
                }
            }
            //free resource for op3;
            delete [] p3;
        }
        //free resource for op2;
        delete [] p2;
    }
    return error;
}

Wenn Sie diesen Code ohne RAII (vergessen Sie das Problem der Ausnahmen!) mit mehreren Exits schreiben, müssen die Löschungen mehrfach geschrieben werden. Wenn Sie ihn mit }else{ dann wird es ein bisschen hässlich.

Aber RAII macht das Problem der Mehrfachausgangsressourcen überflüssig.

1voto

BJS Punkte 1

Ich vermeide immer mehrere Return-Anweisungen. Auch in kleinen Funktionen. Kleine Funktionen können größer werden, und die Verfolgung mehrerer Rückgabewege macht es (für meinen kleinen Verstand) schwieriger, den Überblick zu behalten, was vor sich geht. Ein einziger Rücksprung macht auch die Fehlersuche einfacher. Ich habe gelesen, dass die einzige Alternative zu mehreren Return-Anweisungen ein unübersichtlicher Pfeil von verschachtelten IF-Anweisungen ist, die 10 Ebenen tief sind. Ich stimme zwar zu, dass eine solche Kodierung vorkommt, aber sie ist nicht die einzige Option. Ich würde nicht die Wahl zwischen mehreren Rückgabeanweisungen und einer Verschachtelung von IFs treffen, sondern sie so umgestalten, dass beides wegfällt. Und das ist mein Code. Der folgende Code beseitigt beide Probleme und ist meiner Meinung nach sehr einfach zu lesen:

public string GetResult()
{
    string rv = null;
    bool okay = false;

    okay = PerformTest(1);

    if (okay)
    {
        okay = PerformTest(2);
    }

    if (okay)
    {
        okay = PerformTest(3);
    }

    if (okay)
    {
        okay = PerformTest(4);
    };

    if (okay)
    {
        okay = PerformTest(5);
    }

    if (okay)
    {
        rv = "All Tests Passed";
    }

    return rv;
}

3 Stimmen

Das Hinzufügen einer Markierung zum Code ist aus analytischer Sicht gleichbedeutend mit zwei Kopien des Codes - eine, bei der die Markierung als falsch angenommen wird, und eine, bei der sie als wahr angenommen wird -, zwischen denen jedes Mal hin und her gesprungen wird, wenn die Markierung geändert wird. Durch das Hinzufügen von Flags wird der Code zwar manchmal weniger umfangreich, aber die analytische Komplexität wird dadurch nicht verringert. Beachten Sie, dass in Fällen wie dem obigen Beispiel das Hinzufügen eines Flags zu einer ausführbaren Datei führt, die größer und langsamer ist als diejenige, die man ohne Flag erhalten könnte.

2 Stimmen

Warum nicht okay = PerformTestOne() && PerformTest2() && PerformTest3() ... IIRC, '&&' wird Kurzschluss auf die erste von diesen, um false zurückgeben, so dass selbst wenn die Tests teuer sind, Sie nicht alle von ihnen durchführen.

0 Stimmen

@MichaelBlackburn Ich denke, das hat etwas damit zu tun, wie Sie denken. Wenn Sie es auf Ihre Weise tun, können Sie nicht in einem bestimmten Debug-Stil debuggen, wo Sie nur während des Debugs sehen wollen, was jede Methode zurückgibt, ohne sie einzugeben.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X