Go: Vorschlag: Go 2: Bare Return entfernen

Erstellt am 3. Aug. 2017  ·  52Kommentare  ·  Quelle: golang/go

(Ich konnte kein bestehendes Problem dafür finden, also bitte schließen, wenn es sich um ein Duplikat handelt und ich es übersehen habe.)

Ich schlage vor, die nackten Renditen loszuwerden. Benannte Rückgabewerte sind großartig, behalten Sie diese bei. Bare Returns sind mehr Ärger als sie wert sind, beseitigen Sie sie.

Go2 LanguageChange NeedsDecision Proposal

Hilfreichster Kommentar

Rückgabe von Nullen überall ist ein wenig ausführlich, findest du nicht?

Einfachheit schlägt Ausführlichkeit. Ein Haufen return nil ist viel einfacher zu verstehen als ein Haufen return bei dem man den neuesten Wert der Variablen verfolgen und sicherstellen muss, dass er nicht überschattet wurde (absichtlich oder von Fehler.)

Alle 52 Kommentare

Ich wäre aus mehreren Gründen gegen diese Änderung.

1) Es ist eine relativ bedeutende syntaktische Änderung. Dies könnte bei den Entwicklern zu Verwirrung führen und dazu beitragen, Go in das gleiche Durcheinander zu bringen, das Python durchgemacht hat.

2) Ich denke nicht, dass sie nutzlos sind, warum machen sie mehr Ärger, als sie wert sind? return nil s überall ist ein wenig ausführlich, findest du nicht?

@awnumar für 2, das passt gut zu #21182

Rückgabe von Nullen überall ist ein wenig ausführlich, findest du nicht?

Einfachheit schlägt Ausführlichkeit. Ein Haufen return nil ist viel einfacher zu verstehen als ein Haufen return bei dem man den neuesten Wert der Variablen verfolgen und sicherstellen muss, dass er nicht überschattet wurde (absichtlich oder von Fehler.)

Beachten Sie, dass Sie mit nackten Rückgaben eine Sache tun können, die Sie sonst nicht erreichen können: Einen Rückgabewert in einer Verzögerung ändern. Zitieren des Code-Review-Kommentare-Wiki :

Schließlich müssen Sie in einigen Fällen einen Ergebnisparameter benennen, um ihn in einem verzögerten Abschluss zu ändern. Das ist immer in Ordnung.

Ein vollständiger Vorschlag zur Abschaffung nackter Rücksendungen sollte erläutern, wie solche Verwendungen stattdessen geschrieben werden sollten und warum die alternative Form vorzuziehen (oder zumindest akzeptabel) ist. Die offensichtlichen Überarbeitungen beinhalten in der Regel viele Boilerplates und Wiederholungen, und obwohl sie normalerweise eine Fehlerbehandlung beinhalten, ist der Mechanismus allgemein.

Ich glaube das nicht

func oops() (string, *int, string, error) {
    ...
    return "", nil, "", &SomeError{err}
}

ist lesbarer als

func oops() (rs1 string, ri *int, rs2 string, e error) {
    ...
    e = &SomeError{err}
    return
}

,Verzeihung.

OTOH - ja, Schattenbildung ist scheiße. Es wäre nicht sinnvoll, es direkt zu verbieten (generierter Code kommt mir in den Sinn), aber ich würde gerne dafür stimmen, dass zumindest das Shadowing von Rückgabewertnamen verboten ist. Oh, und in allen anderen Fällen wäre es auch schön, den Compiler dazu zu bringen, eine Diagnose zu generieren :)

Edit: anscheinend gibt es #377, die darüber spricht

@josharian Ich ging davon aus, dass verzögerte Funktionen die Rückgabevariablen immer noch ändern könnten. Diese Semantik scheint mehr oder weniger orthogonal zur Syntax der return-Anweisung zu sein.

@josharian Sie benötigen benannte Rückgabeparameter, um sie in einer verzögerten Funktion ändern zu können. Sie müssen dafür keine nackte Rücksendung verwenden. return mit expliziten Werten kopiert die Werte in die benannten Rückgabewerte, bevor die verzögerten Funktionen ausgeführt werden.

@bcmills @dominikh richtig, dumm von mir. Geistiger Verfall; danke, dass du mich klargestellt hast.

Ein func ohne Rückgabewerte sollte immer noch in der Lage sein, return zu "entblößen":

func noReturn() {
    if !someCondition() {
        return // bail out
    }
    // Happy path
}

Ich verbrachte 1,5 Minuten damit, den folgenden Go-Code in der Go-Standardbibliothek (von vor 4 Jahren , /cc @bradfitz) anzuschauen, ungläubig, da ich dachte, dass es sich um einen schlimmen Fehler handeln könnte:

https://github.com/golang/go/blob/2d69e9e259ec0f5d5fbeb3498fbd9fed135fe869/src/net/http/server.go#L3158 -L3166

Konkret dieser Teil:

tc, err := ln.AcceptTCP()
if err != nil {
    return
}

Auf den ersten Blick sah es für mich so aus, dass in der ersten Zeile dort die neuen Variablen tc und err mit einer kurzen Variablendeklarationssyntax deklariert wurden, im Unterschied zum benannten err error Return Variable. Dann sah es für mich so aus, als würde die bloße Rendite tatsächlich nil, nil anstatt nil, err wie es hätte sein sollen.

Nach ungefähr 90 Sekunden langem Nachdenken wurde mir klar, dass es sich tatsächlich um korrekten Code handelt. Da sich der benannte Rückgabewert err error im selben Block wie der Funktionsrumpf befindet, deklariert die kurze Variablendeklaration tc, err := ... nur tc als neue Variable, aber kein neues err Variable, also wird die benannte err error Rückgabevariable durch den Aufruf von ln.AcceptTCP() , sodass das bloße return tatsächlich einen Nicht-Null-Fehler zurückgibt sollen.

(Wäre es in einem neuen Block gewesen, wäre es tatsächlich ein Kompilierungsfehler "err wird während der Rückgabe gespiegelt", siehe hier .)

Ich denke, das wäre viel klarer und lesbarer Code gewesen:

tc, err := ln.AcceptTCP()
if err != nil {
    return nil, err
}

Ich wollte diese Geschichte teilen, weil ich denke, dass sie ein gutes Beispiel dafür ist, wie reine Renditen Programmiererzeit verschwenden. Meiner Meinung nach sind nackte Rückgaben geringfügig einfacher zu schreiben (es spart nur ein paar Tastenanschläge), führen jedoch oft zu Code, der schwerer zu lesen ist als gleichwertiger Code, der vollständige Rückgaben verwendet (nicht nackt). Go macht normalerweise das Richtige bei der Optimierung für das Lesen, da dies viel häufiger (von mehr Leuten) als beim Schreiben geschieht. Es scheint mir, dass die Bare-Return-Funktion zu einer geringeren Lesbarkeit neigt, daher könnte es sein, dass das Entfernen in Go 2 die Sprache verbessern würde.

Haftungsausschluss: In Go-Code, den ich am häufigsten schreibe und lese, neige ich dazu, bloße Returns zu vermeiden (weil ich denke, dass sie weniger lesbar sind). Aber das bedeutet, dass ich weniger Erfahrung mit dem Lesen/Verstehen von bloßen Returns habe, was meine Fähigkeit, sie zu lesen/zu analysieren, negativ beeinflussen könnte. Es ist ein bisschen Fang-22.

@shurcooL , interessantes Beispiel, das mich auch abgeschreckt hat. Für mich war es die Tatsache, dass es zwei Verbindungsvariablen tc und c . Ich dachte, Sie haben beim Kopieren und Einfügen des Codes einen Fehler gemacht und anstelle von c sollte tc . Ich brauchte ungefähr die gleiche Zeit, um zu erkennen, was dieser Code macht.

Aus dem Artikel:

Beachten Sie, dass Sie return oi können, wenn Sie die von Golang angebotene nackte Rendite nicht mögen oder bevorzugen, während Sie immer noch den gleichen Vorteil erhalten:

Benannte Rückgabewerte sind großartig! Die bloße Rückgabe von benannten Rückgabewerten ist das Problem. :-)

@awnumar , das ist nicht relevant. Siehe meinen Kommentar zu Hacker News: https://news.ycombinator.com/item?id=14668595

Ich denke, diese zu entfernen würde dem Ansatz der expliziten Fehlerbehandlung folgen. Ich benutze sie nicht.

Code, den ich auf Golang-Nuts mit bloßen Returns überprüft habe, ist nicht schwer zu verstehen, aber das Parsen des Variablenbereichs ist für die Leser ein unnötiger zusätzlicher Aufwand.

Ich liebe Bared Return, besonders wenn eine Funktion mehrere Returns hat. Es macht den Code nur viel sauberer. Der Hauptgrund, warum ich mich für go entschieden habe.

Das Go-Tool Vet Shadow kann potenzielle Shadowing-Variablen erkennen. Wenn eine Funktion weniger zyklomatische Komplexität hat, plus einige Testfälle. Ich konnte nicht erkennen, dass es Probleme geben wird. Ich könnte mich irren, aber ich möchte einige Beispiele sehen, um zu zeigen, wie schlecht die nackte Rendite sein kann.

Ich möchte einige Beispiele sehen, um zu zeigen, wie schlecht die nackte Rendite sein könnte.

@kelwang Hast du mein Beispiel zu ln.AcceptTCP() aus 7 Kommentaren oben gesehen?

Hallo @shurcooL , thx

Ja, ich denke, Sie haben einen großen Punkt gemacht.
Aber wie gesagt, es ist 4 Jahre her. Ich habe das Gefühl, dass du dich vielleicht schon daran gewöhnt hast.

Ich denke, es ist nicht wirklich ein Problem für die nackte Rückkehr. Aber eine Verwirrung bei der Initialisierung mehrerer Variablen.

Für mich funktioniert das Schattentierarzt-Tool normalerweise sehr gut. Darüber mache ich mir nie wirklich Sorgen.
Vielleicht sollten wir ein Ticket in go Linter ausfüllen, um diese Art von Verwirrung zu vermeiden. ob Sie den Fehler umbenennen oder zuerst tc oben deklarieren. Ich denke, ein Linter-Vorschlag sollte gut genug sein.

@kelwang Meiner Meinung nach, wenn eine Funktion mehrere Rückgaben bis zu dem Punkt hat, an dem die Rückgabeanweisungen hässlich werden, sollte stattdessen eine Struktur / ein Zeiger auf eine Struktur über eine bloße Rückgabe zurückgegeben werden.

Da #377 erwähnt wurde, würde ich argumentieren, dass die Ursache der Verwirrung im ln.AcceptTCP Beispiel eher in der Magie hinter := als in der bloßen Rendite selbst.

Ich denke, der Fall ln.AcceptTCP wäre mit einer expliziteren Form der kurzen Deklaration ( vorgeschlagen in der referenzierten Ausgabe) nicht so schlimm:

func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
    :tc, err = ln.AcceptTCP()
    if err != nil {
        return
    }
    // ...
}

Wenn Sie sich nur eine Multivariable := ansehen, können Sie nicht erkennen, welche Variablen deklariert werden: Sie müssen den gesamten vorangehenden Teil des Blocks berücksichtigen, um dies zu wissen.
Ein Versehen darüber, wo die Blockgrenze ist, und Sie können am Ende einen schwer zu findenden Fehler haben.
Außerdem können Sie eine Multivariable := nicht so einstellen, dass sie genau das deklariert, was Sie wollen; Sie sind gezwungen, die Kurzdeklaration aufzugeben oder den Code neu zu organisieren.

Ich habe viele Vorschläge gesehen, die versuchten, spezifische Konsequenzen daraus zu lösen, aber ich denke, die Wurzel des Problems liegt einfach in der fehlenden Deutlichkeit von := (ich würde auch argumentieren, dass Shadowing immer dann, wenn es als Fallstrick betrachtet wird, es ist wirklich nur die Schuld von Multi-Variablen := ).

Ich sage nicht, dass sich die bloße Rendite unbedingt lohnt, ich sage nur, dass das, was wir sehen, ein komplexes Problem ist.

Unabhängig von den Lesbarkeitsargumenten denke ich, dass die bloße Rendite weniger logisch konsistent und elegant ist. Es ist irgendwie ein wackeliger Standpunkt. Allerdings bin ich natürlich nicht der einzige, der hier subjektiv ist.

@tandr Ich denke, die Rückgabe eines kleinen Strukturobjekts ist viel klarer, als mehr als drei Rückgabewerte zu haben.

Alternative zu einer reinen Rendite, obwohl in #21182 debattiert und zugunsten von #19642 aufgegeben:

func f() (e error) {
   return ... // ellipsis trigram
}

Während ich dafür bin, es in Go2 zu entfernen, habe ich #28160 gemacht, um es (im Wesentlichen) in Go1 über gofmt entfernen. Leute Kommentare dort wären dankbar! 😄

Ich habe festgestellt, dass nackte Returns im DB-Layer überraschend hilfreich sind.

Dies ist ein echter redigierter Produktionscode -

func (p *PostgresStore) GetSt() (st St, err error) {
    var tx *sql.Tx
    var rows *sql.Rows
    tx, err = p.handle.Begin()
    if err != nil {
        return
    }
    defer func() {
        if err != nil {
            tx.Rollback()
        } else {
            tx.Commit()
        }
        rows.Close()
    }()

    rows, err = tx.Query(`...`)
    if err != nil {
        return
    }
    // handle rows
    for rows.Next() {
        var all Call
        err = rows.Scan(&all.Email, &all.Count)
        if err != nil {
            return
        }
        st.Today = append(st.Today, &all)
    }

    rows.Close()
    rows, err = tx.Query(`...`)
    if err != nil {
        return
    }
    // handle rows
    for rows.Next() {
        var all Call
        err = rows.Scan(&all.Email, &all.Count)
        if err != nil {
            return
        }
        st.Books = append(st.Books, &all)
    }
    return
}

Es gibt hier 6 Return-Anweisungen. (Eigentlich gibt es noch 2 weitere, ich habe den Code nur der Kürze halber gekürzt). Aber mein Punkt ist, wenn ein Fehler auftritt, überprüft der Aufrufer nur die Variable err . Wenn ich nur return err schreiben müsste, wäre ich immer noch in Ordnung, aber um der Rückgabesignatur zu entsprechen, muss ich immer wieder return st, err schreiben. Und dieser wächst linear, wenn Sie mehr Variablen zurückgeben müssen; Ihre Rücksendeerklärung wird immer größer und größer.

Wenn es jedoch benannte Rückgabeparameter gibt, rufe ich einfach return auf, da ich weiß, dass es auch alle anderen Variablen in dem Zustand zurückgibt, in dem sie sich befanden. Das freut mich und ich halte es für ein tolles Feature.

@agnivade nicht sicher, ob dies daran liegt, dass er

@agnivade fünf Ihrer sechs Rücksendungen sollten unter dem bevorstehenden Go2-Fehlerbehandlungsschema verschwinden :-)

Mehr dazu im Feedback-Wiki .

@nhooyr - Oh je .. sieht aus, als ob wir heute einen Prod-Push machen .. :man_facepalming: :sweat_smile:

@networkimprov - Das stimmt. An die neue Fehlerbehandlung hatte ich nicht gedacht. Persönlich wäre ich damit einverstanden, _wenn_ die neue Fehlerbehandlung landet. Aber selbst dann denke ich, dass dies eine ziemlich große Änderung ist, die viele Codebasen zerstören wird. Wir können dies wohl mit automatisierten Werkzeugen beheben. Aber ich frage mich, wie viele dieser großen Änderungen für Go 2 vorgenommen werden sollten.

Go2 erhält die Lizenz, nicht abwärtskompatibel mit Go1 zu sein, nicht wahr?

Ich stimme zu, dass Tools bereitgestellt werden können, um den vorhandenen Go1-Code so zu aktualisieren, dass er mit dieser Änderung in Go2 kompatibel ist.

Go2 erhält die Lizenz, nicht abwärtskompatibel mit Go1 zu sein, nicht wahr?

Es ist fast sicher, dass wir diese Lizenz nicht verwenden werden. Die Abwärtskompatibilität zu durchbrechen ist unglaublich schwierig und riskant in Bezug auf das Ökosystem.

Wenn derzeit keine Breaking Changes geplant sind, würde ich zustimmen, dass dieser Vorschlag keine Unterbrechung wert ist. Ich hoffe, wir berücksichtigen den Vorschlag, wenn/wenn grundlegende Änderungen geplant sind. go fix zu aktualisieren, um diesem Vorschlag gerecht zu werden, sollte trivial sein.

Neue Schlüsselwörter für die Go2-Fehlerbehandlung sind auf dem Tisch, und das würde einige Codes zerstören.

Für Go 2 können wir Code knacken, wenn es sich lohnt, aber es ist mit hohen Kosten verbunden. Die Kosten für ein neues Schlüsselwort sind geringer als der Code zum Entfernen eines Sprachfeatures, da es einfach zu diagnostizieren und zu beheben ist. Man kann sich vorstellen, dass der Nutzen des neuen Schlüsselworts die Kosten übersteigen würde, Code leicht umschreiben zu müssen, der einen Bezeichner verwendet, der mit dem Schlüsselwort identisch ist.

Dieser Fall ist schwieriger umzuschreiben als ein neues Schlüsselwort, aber er ist machbar. Ich denke, die wichtigste Frage ist: Verstehen die Leute falsch, was es bedeutet, wenn sie eine nackte Rückkehr schreiben? Gibt es echte Fehler in Programmen aufgrund der Verwendung eines nackten Returns? Selbst wenn es keine echten Fehler gibt, machen die Leute beim Schreiben von Code Fehler, indem sie eine nackte Rückgabe falsch verwenden?

Gibt es echte Fehler in Programmen aufgrund der Verwendung eines nackten Returns?

Ich bin mir nicht sicher, ob es Produktionsfehler verursacht, aber wenn ich die nackte Rückkehr sehe, muss ich normalerweise innehalten, um herauszufinden, was passiert. Ich werde paranoid, dass beschattende err auf unerwartete Weise arbeiten, weil ich nicht 100% sicher bin, wie sie interagieren. Es macht das Lesen des Codes viel langsamer.

Trotzdem denke ich, dass #28160 wahrscheinlich eine bessere Lösung ist, da es abwärtskompatibel ist und gofmt bereits einige kleinere Änderungen vorgenommen hat.

Ich werde paranoid, dass Schattenfehler auf unerwartete Weise arbeiten

Ich habe erst vor kurzem herausgefunden, dass man sich um das Shadowing eigentlich nicht so viele Sorgen machen muss, wie ich dachte , zumindest nicht was Bugs angeht. Es ist eigentlich ein Kompilierzeitfehler, eine bloße Rückgabe zu verwenden, wenn eine der Rückgabevariablen an dem Punkt, an dem return auftritt, überschattet wird.

Und bevor irgendjemand etwas sagt, ja, ich weiß, dass es viele andere Probleme mit diesem Beispiel gibt. Ich habe nur etwas zusammengeworfen, um es zu demonstrieren.

28160 wurde geschlossen, was mir die Tür zur Behebung dieses Problems in Go1 zu schließen scheint.

Nun, diese Art von Veränderung würde in Go 1 sowieso nie passieren, egal wie man es angeht.

Vielleicht liegt das Problem in := , und wir sollten einen Vorschlag haben, es zu entfernen.

Hier geht es nicht nur um Schatten. Es geht darum, den Leser dazu zu bringen, mehr Kontext als nötig zu tragen.

Verwenden Sie das Codebeispiel hier: https://github.com/golang/go/issues/21291#issuecomment -320120637

Im ersten Beispiel weiß der Leser genau, was zurückgegeben wird, da er nur den Wert von err verfolgen muss.

Im zweiten Beispiel müsste der Leser die Werte von drei zusätzlichen Variablen verfolgen.

Anders ausgedrückt

if err != nil {
    return err
}
...
return err

vs

if err != nil {
    return err
}
...
return nil

(eine Variable mit dem Wert nil zurückgeben vs. nil zurückgeben)

Was bevorzugen Sie?

Ich bevorzuge letzteres, weil es auf den ersten Blick eindeutig und leichter zu verstehen ist. Das Entfernen von Bare Returns würde explizite Rückgabewerte fördern, anstatt Rückgabewerte zu fördern, die abgeleitet werden müssen.

Ein weiteres Beispiel für die kognitive Belastung ist, dass man eine leere Funktion ( func(arg T) ) nicht von einer nicht leeren Funktion ( func(arg T) ret R ) unterscheiden kann, wenn man sich eine bloße Rückgabe ansieht. Es kann sein, dass die Funktion keine Rückgabewerte hat oder dass sie benannte Werte hat, die zurückgegeben werden. Sie müssen sich die Funktionssignatur merken, um zu wissen, was die Rückgabe tatsächlich bedeutet. Kein großes Problem, sicher, aber es ist eine weitere Sache, die Sie im Kopf behalten sollten.

Bare-Return-Anweisungen können in einigen Fällen verwirrend sein. Aber es gibt auch spezielle Fälle, in denen sie nützlich sind. Und natürlich funktionieren sie heute, was ein starkes Argument dafür ist, sie zu behalten.

Die beste Lösung hier ist wahrscheinlich, in der Sprache bloße Zeilenumbrüche beizubehalten, aber erwägen Sie, eine Lint-Prüfung hinzuzufügen, die vor der Verwendung in komplexen Fällen warnt, in denen Shadowing auftritt.

Dies ist mein genauer Gedanke, wenn ich mit dem Lesen einer Go-Codebasis beginne.
Die Kurzversion sollte gut für Hacker sein, die schnell codieren, hier und da mit der Syntax herumtricksen und den Opfercomputer vergiften wollen.
Aber in Bezug auf Unternehmensanwendungen kann die Einsparung von wenigen Tastenanschlägen Millionen kosten, um sie zu erkennen

Bearbeiten: Ich möchte klarstellen, dass mein Vorschlag darin besteht, die bloße Rückgabe für Funktionen zu deaktivieren, die einen Wert zurückgeben, und die bloße Rückgabe für die void-Funktion unverändert zu lassen.

Ich bin also auf einige Beispielcodes ohne Rückgabe von 2017 gestoßen. Mit go 1.12.5 (windows/amd64) wird dies bei go build als fehlende Rückgabe gekennzeichnet. Ist das das gleiche Problem? Waren implizite Rückgaben in der Vergangenheit erlaubt und jetzt ungültig? Ich konnte es nicht mit einer bloßen Rückkehr beheben. Der Typ war uintptr, also habe ich 0 zurückgegeben (nill würde nicht fusseln).

@datatribe , mir

@datatribe , mir

Es ist durchaus möglich, dass der Beispielcode nicht gut war. Danke @bradfitz

Ich bin mir nicht sicher, ob es Produktionsfehler verursacht, aber wenn ich die nackte Rückkehr sehe, muss ich normalerweise innehalten, um herauszufinden, was passiert. Ich werde paranoid, dass beschattende err auf unerwartete Weise arbeiten, weil ich nicht 100% sicher bin, wie sie interagieren. Es macht das Lesen des Codes viel langsamer.

Da stimme ich dir zu. Es lässt mich innehalten, um herauszufinden, welche Werte den benannten Parametervariablen zugewiesen sind. Mein unangenehmes Lesen (besonders bei langen) Funktionen bei nackten Rückgaben ist, dass ich nicht leicht verfolgen kann, was tatsächlich zurückgegeben wird. Jede nackte Rückgabe bedeutet tatsächlich return p1, p2, ..., pn für benannte Parameter, aber manchmal sind die Werte einiger Parameter offensichtlich wörtlich wie return nil, nil , return nil, err , return "", err und return p, nil statt return p, err . Wenn ich return nil, err schreibe, könnte err immer noch nil wert sein, aber es ist klar, dass der erste Rückgabewert nil . Wenn die nackte Rückgabe nicht zulässig ist, schreibt der Schreiber eher literale Werte in die return-Anweisung, wenn dies möglich ist. Tatsächlich haben sie alle wörtliche Werte verwendet, als ich sie bat, während der Codeüberprüfungen nackte Rückgaben zu vermeiden.

Wenn Schriftsteller in nackten Rücksendungen schreiben, neigen sie dazu, nicht darüber nachzudenken, was zurückgegeben wird. Als ich sie aufforderte, nackte Rückgaben zu vermeiden, denken sie jetzt über den tatsächlichen Wert nach, den sie zurückgeben möchten, und stellen fest, dass sie falsche Werte wie teilweise konstruierte Werte zurückgegeben haben. Ist explizit nicht besser als implizit?

Ich weiß, dass es empfohlen wird, Fehlerflüsse einzurücken, aber nicht jeder folgt diesem Muster in der Realität, insbesondere Leute, die gerne lange Funktionen mit vielen nackten Rückgaben schreiben. Manchmal ist es schwer zu erkennen, ob es sich um einen Fehlerfluss handelt oder nicht, wenn man viele nackte Rückgaben sieht. Ich lese den Code sorgfältig, dekodiere ihn und konvertiere nackte Rückgaben mit einigen Literalwerten in nicht nackt, dann ist es viel einfacher zu lesen. (manchmal ist es nicht möglich, die Literalwerte herauszufinden, wenn der Code komplex ist)

Ich weiß, dass der Kommentarblock der Dokumentation erwähnt, was er für einige sinnvolle Bedingungen zurückgibt, aber nicht jeder tut dies. Bei einer return-Anweisung mit einigen Literalwerten kann ich das leicht verfolgen, indem ich mir den Code anschaue.

Ich weiß, dass wir benannte Parameter und nicht-nackte Rückgaben zusammen verwenden können, aber das weiß nicht jeder. Ich sehe oft so etwas wie das Folgende, und ich denke, return io.EOF ist besser.

err = io.EOF
return

Trotzdem denke ich, dass #28160 wahrscheinlich eine bessere Lösung ist, da es abwärtskompatibel ist und gofmt bereits einige kleinere Änderungen vorgenommen hat.

Ich stimme dem anderen Vorschlag nicht zu, dass gofmt sie zurücksetzen sollte, auch wenn das die Aufgabe von gofmt . Das liegt daran, dass nur ein paar return p1, ..., pn mechanisch den Code verständlicher machen.

Es ist möglich, dass Fusseltools dies überprüfen können ( nakedret tut das), aber IMO hat die nackte Rückgabe mehr Schaden als Nutzen. Ich stimme auch zu, dass der Nutzen des Entfernens von Naked Return geringer sein kann als der Schaden, der die Kompatibilität beeinträchtigt. Aber ich denke, es ist einfach mit go fix zu beheben, auch wenn mechanische go fix den Code nicht lesbar machen.

Go ist meiner Meinung nach eine sehr klare und lesbare Sprache. Und die nackte Rückkehr ist ein kleiner Teil der Sprache, der es mir schwer macht, den Code zu verstehen.

Änderung https://golang.org/cl/189778 erwähnt dieses Problem: cmd/go/internal/get: propagate parse errors in parseMetaGoImports

Ich bin zwar in der Minderheit, möchte aber eigentlich das Gegenteil vorschlagen. Funktionen mit benannten Rückgaben sollten immer die bloße Rückgabe verwenden. Ansonsten sieht es so aus, als ob der Code lügt. Sie weisen Werte zu und überschreiben sie dann möglicherweise stillschweigend bei der Rückkehr. Hier ist ein schlechter Code, um zu veranschaulichen, was ich meine,

func hello() (n, m int) {
    n = 2
    m = 3
    return m, n
}

Wenn Sie dort nur einen bloßen Return verwenden würden, macht der Code wieder Sinn.

@millerlogic Ich denke, das wäre viel zu aggressiv. Zum Beispiel ist nichts falsch an Code wie:

func documentedReturns() (foo, bar string, _ error) {
    [...]
    if err != nil {
        return "", "", fmt.Errorf(...)
    }
}

Ich denke auch, dass Ihr Punkt am besten als separater Gegenvorschlag passen könnte, da Sie das Gegenteil von dem vorschlagen, was der aktuelle Vorschlag vorbringt.

@mvdan Guter Punkt, ich denke, es gibt einen Mittelweg, bei dem es nicht darum geht, sie zu dämonisieren. Ich glaube, ich habe eine ähnliche Idee gelesen: keinen Wert explizit zurückzugeben, wenn Sie zuvor der Rückgabevariablen zugewiesen haben. Es könnte sogar irgendwo implementiert werden, aber ich habe es nie getroffen. Das würde also bedeuten, dass mein hallo-Beispiel ohne eine nackte Rückkehr fehlschlagen würde, und Ihr Beispiel würde erfolgreich sein, weil foo oder bar nicht zugewiesen wurden.

Ich denke, diese sollten aus der Tour von go entfernt werden, damit neuere go-Entwickler nicht dazu ermutigt werden, diese zu verwenden. In der Praxis sind sie nur eine kognitive Steuer. Bei den wenigen, die ich gesehen habe, musste mein Gehirn immer sagen "Warte was?! ... oh ja, nackte Rückgaben und benannte Rückgabewerte". .

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen