Go: Vorschlag: Go 2: Fügen Sie einen ternären Bedingungsoperator hinzu

Erstellt am 18. Juli 2019  ·  78Kommentare  ·  Quelle: golang/go

Ich bin mit der Go-Konvention und den Argumenten der Sprachdesigner hier nicht einverstanden https://golang.org/doc/faq#Does_Go_have_a_ternary_form und denke, dass es sich um ein wirklich fehlendes Feature in der Sprache handelt.

Betrachten Sie in C den folgenden Code:

printf("my friend%s", (nbFriends>1?"s":""));

oder in C++:

std::cout << "my friend" << (nbFriends>1?"s":"") << std::endl;

In Go verursacht es entweder riesige Wiederholungen, die Fehler verursachen können, oder sehr ausführlichen und ineffizienten Code oder beides, für etwas, das einfach sein sollte:

Lösung 1:

// horribly repetitive, risk of divergence between the two strings
if nbFriends > 1 { 
  fmt.Printf("my friends\n") 
} else { 
  fmt.Printf("my friend\n")
}

Lösung 2:

// difficult to read
fmt.Printf("my friend")
if nbFriends > 1 { fmt.Printf("s") }
fmt.Printf("\n")

Lösung 3:

// difficult to read
var plural = ""
if nbFriends > 1 { plural = "s" }
fmt.Printf("my friend%s\n", plural)

Lösung 4:

// dangerous (ifTrue and ifFalse are both evaluated, 
// contrary to a real ternary operator), 
// and not generic at all (works only for strings)
func ifStr(condition bool, ifTrue string, ifFalse string) string {
  if condition { 
    return ifTrue
  }
  return ifFalse
}
fmt.Printf("my friend%s\n", ifStr(nbFriends > 1, "s", ""))

Lösung 5:

// horrible to read, probably inefficient
fmt.Printf("my friend%s\n",
        func(condition bool) string {
            if condition {
                return "s"
            }
            return ""
        }(nbFriends > 1))
Go2 LanguageChange Proposal Proposal-FinalCommentPeriod

Hilfreichster Kommentar

Ich denke, das Beispiel ist ziemlich schlecht, wenn man bedenkt, dass es nur um ein Zeichen geht und meiner Meinung nach nicht wirklich lesbar ist (?:"s":"")
Aber ich stimme zu, dass der ternäre Operator hinzugefügt werden sollte, es ist für mich ein Kinderspiel
und ich habe mir einige Beispiele ausgedacht, die für mich persönlich nützlich wären, und ich denke, Sie können sich auf einige davon beziehen.

const PORT = production ? 80 : 8080
anstatt

const PORT = -1
if production {
    PORT = 80
else {
    PORT = 8080
}

fmt.Printf("Running %s build!", production ? "Production" : "Debug") .. etc

Aber natürlich ist der ternäre Operator sehr schwer zu lernen.

Alle 78 Kommentare

@gopherbot , Label Go2, LanguageChange hinzufügen

Siehe auch #31659 und #32860.

Diese Entscheidung wurde, wie Sie bemerken, bereits in einem FAQ verankert. Wenn Sie argumentieren wollen, dass die FAQ-Antwort geändert werden sollte, brauchen Sie mehr als ein paar Beispiele. Ich verspreche Ihnen, dass wir diese Beispiele bereits gesehen und berücksichtigt haben. Was Sie brauchen, sind Daten: echte Programme mit Code, der durch Hinzufügen eines bedingten Operators einfacher und leichter lesbar wird. Sie brauchen auch Argumente gegen die allgemeinen Bedenken bezüglich des Bedingungsoperators, etwa dass er den Code schwerer lesbar macht, insbesondere wenn er verschachtelt ist.

Auch ein kleiner Punkt, aber Ihr Beispiel ist nicht großartig, da es nur für Englisch funktioniert und die Lokalisierung von Nachrichtenzeichenfolgen nicht unterstützt.

@ianlancetaylor

In #31659 haben Sie meiner Meinung nach einen sehr guten Gegenvorschlag gemacht, eine eingebaute cond -Funktion zu haben, um ternäre Funktionalität bereitzustellen. Dies musste integriert sein (im Gegensatz zu einer generischen Funktion), um eine Kurzschlussauswertung der Wahr/Falsch-Argumente zu ermöglichen. Es litt immer noch unter der Möglichkeit, dass Leute cond -Funktionen verschachteln könnten, obwohl ich das persönlich nicht als fatales Problem ansah, denn selbst wenn sie es taten, sollte es immer noch besser lesbar sein als die Hieroglyphen des ternären Operators von C selbst .

Da dieser Vorschlag nun abgeschlossen wurde, beabsichtigen Sie, diesen Vorschlag weiter zu verfolgen, oder haben Sie die Idee einer alternativen ternären Form insgesamt aufgegeben?

Ich persönlich habe nicht die Absicht, diese Idee weiter voranzutreiben. Das war eher ein Diskussionsgedanke als ein ernsthafter Vorschlag. Natürlich habe ich nichts dagegen, wenn jemand daraus einen echten Antrag machen möchte. Aber um akzeptiert zu werden, müssten wir meiner Meinung nach noch einige Daten darüber sehen, wie sehr es real existierende Programme vereinfachen würde.

Okay, danke für die Klarstellung.

Man muss sich nur den Code in anderen Sprachen der C-Familie ansehen, um zu sehen, wie verbreitet der ternäre Operator ist, aber es wäre schwierig, den Go-Code selbst zu analysieren, da, wie @Phrounz in seinem Eröffnungsbeitrag betonte, eine Reihe von Konstruktionen verwendet werden, um zu funktionieren um seine Abwesenheit.

Unter Verwendung der cond -Idee würde sein Beispiel folgendermaßen aussehen:

fmt.Printf("my friend%s\n", cond(nbFriends > 1, "s", ""))

Abgesehen davon, wenn wir Generika bekommen, wäre ich persönlich damit zufrieden, meine eigene cond -Funktion zu schreiben und sie angesichts des Fehlens von Kurzschlüssen nur dort zu verwenden, wo die Argumente billig auszuwerten sind.

Meiner Meinung nach ist es besser, mehr Code (nur ein paar Zeilen) zu schreiben, als die Regel von x ? a : b herauszufinden. Die if-Anweisung mag ausführlich erscheinen (nicht sicher), aber leicht verständlich.

Außerdem kann ein ternärer Bedingungsoperator leicht missbraucht werden, wenn Leute mehrere verschachtelte x ? a : b schreiben. Der Nutzen der Einführung ist nicht groß genug.

Ich sehe, dass ternäre Operatoren nur in Einzeiler-Funktionen einfach zu visualisieren sind. Selbst dann befassen sie sich die meiste Zeit mit der Fehlerbehandlung, in diesem Fall ist es besser, sich an einen "je weniger Einrückung, desto besser"-Ansatz zu halten, indem der Fehler oder der am wenigsten wahrscheinliche Pfad für eine Funktion in ein if eingeschlossen und dann behandelt wird. im Gegensatz zu einer mehrfachen Verzweigungslogik.

Ich denke, das Beispiel ist ziemlich schlecht, wenn man bedenkt, dass es nur um ein Zeichen geht und meiner Meinung nach nicht wirklich lesbar ist (?:"s":"")
Aber ich stimme zu, dass der ternäre Operator hinzugefügt werden sollte, es ist für mich ein Kinderspiel
und ich habe mir einige Beispiele ausgedacht, die für mich persönlich nützlich wären, und ich denke, Sie können sich auf einige davon beziehen.

const PORT = production ? 80 : 8080
anstatt

const PORT = -1
if production {
    PORT = 80
else {
    PORT = 8080
}

fmt.Printf("Running %s build!", production ? "Production" : "Debug") .. etc

Aber natürlich ist der ternäre Operator sehr schwer zu lernen.

Ja, das ist ein gutes Beispiel, besonders wenn es auf höchstem Niveau ist:

const production = true

//...

const PORT = production ? 80 : 8080

da Sie dann keine init -Funktion benötigen, um PORT zu initialisieren.

Eine eingebaute cond -Funktion _könnte_ als const -Initialisierer verwendet werden, obwohl eine generische Version dies definitiv nicht könnte.

@Terottaja @alanfo

Ich denke, die idiomatische Lösung für dieses spezielle Problem ist die Verwendung von Build Constraints .

@Terottaja

Siehe meinen anderen Kommentar für die Lösung für globale Variablen/Konstanten.

Für lokale Variablen/Konstanten denke ich, die idiomatische Art, diesen Code zu schreiben:

const PORT = -1
if production {
    PORT = 80
else {
    PORT = 8080
}

ist:

PORT := 8080
if production {
    PORT = 80
}

Sie könnten argumentieren, dass ich const in eine var geändert habe, aber ich wäre überrascht, wenn der Compiler nicht schlau genug wäre, um herauszufinden, dass PORT konstant ist, sodass es meiner Meinung nach im echten Code keinen Unterschied macht.

Obwohl es in diesem speziellen Beispiel wahrscheinlich keine Rolle spielen würde, ob PORT ein const oder ein var ist, könnte es allgemeiner wichtig sein. Zum Beispiel, wenn Sie eine ganze Zahl deklarieren, die verwendet werden sollte, um die Größe eines Arrays zu definieren.

Vielleicht sollte ich meine eigene Position zu diesem Vorschlag klarstellen. Obwohl ich persönlich kein Problem mit dem „Standard“-Ternäroperator habe, bin ich mir nicht sicher, ob es eine gute Idee wäre, ihn in dieser Form in Go einzuführen. Ich würde stattdessen ein integriertes cond bevorzugen, das viel besser lesbar ist, obwohl ich realistisch gesehen wenig Chancen sehe, dass beides übernommen wird.

@Terottaja

Siehe meinen anderen Kommentar für die Lösung für globale Variablen/Konstanten.

Für lokale Variablen/Konstanten denke ich, die idiomatische Art, diesen Code zu schreiben:

const PORT = -1
if production {
  PORT = 80
else {
  PORT = 8080
}

ist:

PORT := 8080
if production {
  PORT = 80
}

Sie könnten argumentieren, dass ich _const_ in eine _var_ geändert habe, aber ich wäre überrascht, wenn der Compiler nicht _schlau genug wäre, ™_ herauszufinden, dass _PORT_ konstant ist, so dass es meiner Meinung nach im echten Code keinen Unterschied macht.

Ich spreche nur darüber, wenn Sie eine Menge solcher Dinge in Ihrem Code haben, wäre der ternäre Operator in diesem Fall definitiv sauberer, nur meine Meinung

Meiner Meinung nach ist es besser, mehr Code (nur ein paar Zeilen) zu schreiben, als die Regel von x ? a : b herauszufinden. Die if -Anweisung mag ausführlich erscheinen (nicht sicher), aber leicht verständlich.

Außerdem kann ein ternärer Bedingungsoperator leicht missbraucht werden, wenn Leute mehrere verschachtelte x ? a : b schreiben. Der Nutzen der Einführung ist nicht groß genug.

Es wird immer Leute geben, die ihn missbrauchen, Code kann missbraucht werden, es ist unvermeidlich, aber wird Sie das betreffen? in den meisten Fällen nein

Ich unterstütze diese Funktion, obwohl sie zu Missbrauch im Code führen kann, ist sie wirklich vorteilhaft für Compiler-Optimierungen, wenn man generisches if /else vermeidet und es durch einen ternären Operator ersetzt.
Die Leute haben von Anfang an bitweise Verschiebungen vorgenommen (wer kann ihnen die Schuld geben, und immer noch schlägt niemand vor, bitweise Verschiebungen wegen der Lesbarkeit wegzunehmen), und der ternäre Operator ist heutzutage einfach wichtig.

@Lexkane : Der Compiler verfügt bereits über Optimierungen, die bedingte Bewegungen verwenden. Wir brauchen kein Sprachkonstrukt, um solche Optimierungen zu erzwingen. Der folgende Code verwendet beispielsweise einen:

func f(x, y int) int {
    r := 3
    if x < y {
        r = 7
    }
    return r
}

Wenn Sie bestimmte Fälle haben, in denen eine bedingte Bewegung nicht generiert wird, und Sie der Meinung sind, dass dies der Fall sein sollte, öffnen Sie ein Problem mit dem Code.

Da ich Go und Javascript gleichzeitig in meinem Job verwende, wollte ich schon unzählige Male x ? a : b in Go-Programmen schreiben! Ich hätte es aufschreiben sollen, um all diese Fälle @ianlancetaylor zu zeigen! Es waren alles echte Programme.
Den ternären Operator lernen wir alle in der Schule (nicht einmal an der Universität), also ist er in seiner klassischen Form die natürliche Art, Code zu schreiben und zu lesen.
Wir haben alle gelernt, dass es drei Arten von Operatoren gibt: unäre, binäre und ternäre. Go fehlt ein Typ ohne wirklichen Grund IMO.
Beide Hände für x ? a : b .

Wir haben alle gelernt, dass es drei Arten von Operatoren gibt: unäre, binäre und ternäre. Go fehlt ein Typ ohne wirklichen Grund IMO.

Es gibt jedoch keinen Grund, warum es einen geben muss. „ternary“ ist nur ein englisches Wort, das „aus vier Teilen zusammengesetzt“ bedeutet. Sie könnten genauso gut quaternäre oder quinäre Operatoren haben.

Ich persönlich finde, dass ternäre Operatoren standardmäßig lästig zu lesen sind. Bei unären und binären Operatoren können Sie leicht genau sehen, wo sich alles befindet, aber bei ternären Operatoren ist nicht immer klar, was zu was gehört, besonders wenn Sie anfangen, sie zu verschachteln. Ich kann das Argument dafür sehen, dass sie in bestimmten Situationen sauberer sind, aber außerhalb dieser Situationen sind sie fast immer schlechter. gofmt könnte möglicherweise helfen, aber nur, wenn es bei der Neuformatierung des Codes viel aggressiver wäre, als es ist. Vielleicht könnte eine Art eingeschränkte eingeführt werden, wie das Verbieten von Verschachteln oder Verketten, aber an diesem Punkt bin ich mir nicht sicher, ob es sich wirklich lohnt.

Es wurde bereits gesagt, dass man mit den einfachsten Operatoren das Chaos anrichten kann. Es stimmt, dass Go-Code einfacher zu lesen und zu schreiben ist als Java- oder Javascript-Code. Aber es ist nicht unmöglich, es unlesbar zu machen.
Der ternäre Operator ist also hauptsächlich für Einzeiler gedacht und sollte für diese Fälle verwendet werden.
Andernfalls können Sie "if - then - else" nehmen, es mehrmals verschachteln und Ihren Code durcheinander bringen. Es liegt immer an Ihnen.
Ich denke, dass die Leute die Häufigkeit unterschätzen, in der einzeilige Ausdrücke im Code vorkommen. Manchmal sind sie selten, aber manchmal füllen sie die Hälfte des geschriebenen Codes aus, und im späteren Fall möchte ich den ternären Operator vorzugsweise in der Form haben, in der er in Javascript ist.

Mir gefällt, dass die Ablaufsteuerung in Go im Allgemeinen mit Anweisungen und nicht mit Ausdrücken erfolgt (der Funktionsaufruf ist die offensichtliche Ausnahme). Viele populäre Sprachen streben nach „alles ist ein Ausdruck“, was oft Spaß macht, aber imo ermutigt dazu, „klugen“ Code zu schreiben. Bei Go dreht sich für mich alles darum, Cleverness zu minimieren.

Übrigens, eine andere (grobe) Möglichkeit, einen ternären Ausdruck zu implementieren, ist:

map[bool]string{true: "", false: "s"}[nbFriends == 1]
map[bool]string{true: "", false: "s"}[nbFriends == 1]

netter Trick, aber viel "cleverer" als einfache bekannte Werbung offensichtlich ? : .

Einige klassische Funktionen könnten schädlich sein, aber wir haben uns bereits daran gewöhnt. Wir merken es nicht einmal.

Die Bedingung muss ein Bool sein, also müssen wir manchmal schreiben

x := 0
y := x != 0 ? 1 : 2

Es ist nicht intuitiv. Denn in der if -Anweisung sehen Sie auf den ersten Blick if und wissen, dass es eine Bedingung geben wird.

In einem ternären Ausdruck wissen Sie nur, dass es sich um eine Bedingung handelt, wenn Sie ? sehen. Sie werden überrascht sein und zurückgehen, um die Bedingung erneut zu lesen, wenn sie kompliziert ist.

Es unterbricht den Lesefluss von links nach rechts und von oben nach unten.

Sie könnten argumentieren, dass ich _const_ in eine _var_ geändert habe, aber ich wäre überrascht, wenn der Compiler nicht _schlau genug wäre, ™_ herauszufinden, dass _PORT_ konstant ist, so dass es meiner Meinung nach im echten Code keinen Unterschied macht.

Nun, es macht einen Unterschied, indem es die Konstanz verliert. Bei Const geht es nicht nur um Optimierung. Code weiter unten kann jetzt mit dem Wert herumspielen

Wie wäre es mit: ternär zulassen, aber nicht verschachteln.
Das würde mir gefallen.

Der einzige Grund, warum something ? foo : bar lesbar _scheint_ ist, weil wir es bereits in anderen Sprachen gewohnt sind. Aber auf keinen Fall ist das besser lesbar oder klarer als

if something {
  foo
} else {
  bar
}

speziell für Neulinge, für die Go ihre Muttersprache ist.

Wenn die Lesbarkeit nicht besser ist, besteht der einzige mögliche Gewinn darin, weniger Codezeilen zu schreiben. Für mich scheint das kein ausreichender Grund zu sein, ein alternatives, nicht sehr intuitives Konstrukt für etwas einzuführen, das wir bereits haben.
Wir haben bereits if . Warum eine andere, weniger intuitive Methode hinzufügen, um dasselbe zu tun?

if something {
  foo
} else {
  bar
}

'else' unterbricht auch die Sichtlinie und Lesbarkeit (Sie müssen zurückgehen und die Bedingung erneut lesen). Ich würde besser 'else' zugunsten von '?' loswerden.

Der einzige Grund, warum something ? foo : bar lesbar _scheint_ ist, weil wir es bereits in anderen Sprachen gewohnt sind. Aber auf keinen Fall ist das besser lesbar oder klarer als

if something {
  foo
} else {
  bar
}

Nun, es ist in mehrfacher Hinsicht klarer:

  • es reduziert die Zeremonie auf eine im Wesentlichen triviale Operation,
  • es drückt eine Zuweisung in einer Zeile aus,
  • es erlaubt uns, die Variable als "const" zu belassen (und damit die mentale Belastung und die Möglichkeit, später damit herumzuspielen, zu reduzieren),
  • es sind 5 Zeilen weniger und macht es somit einfacher, mehr Code aufzunehmen.

speziell für Neulinge, für die Go ihre Muttersprache ist.

Warum sollte eine Sprache ihre Ausdrucksfähigkeit auf Neuankömmlinge konzentrieren? Es ist, als würde man eine vereinfachte Benutzeroberfläche nur für Computer-Analphabeten erstellen und damit jeden frustrieren, der einen bestimmten Punkt überschreitet und die zusätzliche Leistung vermisst.

@bugpowder Der ternäre Ausdruck ist vollständig ersetzbar, und die if -Anweisung ist intuitiver, ausdrucksstärker und häufiger.

@bugpowder Der ternäre Ausdruck ist vollständig ersetzbar, und die if -Anweisung ist intuitiver, ausdrucksstärker und häufiger.

Was ist mit ähnlichen Fällen;

println("Example bool is: ", bool ? "true" : "false")
Hier glänzt es wirklich für mich, wo Sie die Anweisung if wirklich nicht verwenden können, es sei denn, Sie möchten, dass Ihr Code so aussieht:

bool := "false" if bool { bool = "true" } println("Example bool is: ", bool ? "true" : "false")

Der einzige Grund, warum something ? foo : bar lesbar _scheint_ ist, weil wir es bereits in anderen Sprachen gewohnt sind. Aber auf keinen Fall ist das besser lesbar oder klarer als

if something {
  foo
} else {
  bar
}

speziell für Neulinge, für die Go ihre Muttersprache ist.

Wenn die Lesbarkeit nicht besser ist, besteht der einzige mögliche Gewinn darin, weniger Codezeilen zu schreiben. Für mich scheint das kein ausreichender Grund zu sein, ein alternatives, nicht sehr intuitives Konstrukt für etwas einzuführen, das wir bereits haben.
Wir haben bereits if . Warum eine andere, weniger intuitive Methode hinzufügen, um dasselbe zu tun?

Als ich das Programmieren lernte, schien der ternäre Operator zunächst etwas seltsam und komplex zu sein, aber nachdem ich ihn weiter nachgeschlagen und diese Beispiele gesehen hatte, wie zum Beispiel:

true ? "it's true!" : "It's false!"
es schien wirklich logisch und einfach, aber das bin nur ich. vielleicht ist es für andere suuuper komplex und schwer zu verstehen.

Ich bin mit der Go-Konvention und den Argumenten der Sprachdesigner hier nicht einverstanden https://golang.org/doc/faq#Does_Go_have_a_ternary_form und denke, dass es sich um ein wirklich fehlendes Feature in der Sprache handelt.

Aber der letzte Satz aus einer FAQ erklärt deutlich 'warum es kein ?:' gibt:

Eine Sprache benötigt nur ein konditionales Kontrollflusskonstrukt.`

Die Fähigkeit, mehr Logik in eine Zeile zu quetschen, ergibt überhaupt nichts Neues. Es gibt bereits eine saubere Möglichkeit, den Kontrollfluss zu ändern, eine andere ist einfach übertrieben.

Schauen wir uns an, was mit dem ternären Ausdruck nicht stimmt. In einem einfachen Fall sind beide ok.

var a, b int
fmt.Println("Example bool is: ", a != 0 && b != 0 ? "true" : "false")
var a, b int
var c string
if a != 0 && b != 0 {
        c = "true"
} else {
        c = "false"
}
fmt.Println("Example bool is: ", c)

Wenn die Dinge komplex werden (eine Bedingung hinzufügen), sieht der ternäre Ausdruck mehrdeutig aus.

Das if-else-Formular erfüllt jedoch seine Aufgabe. Ich denke, eine kürzere Form ist nicht immer die klarere Form.

var a, b, c int
fmt.Println("Example bool is: ", a != 0 && b != 0 ? c != 0 ? "true" : "false" : "false")
var a, b, c int
var d string
if a != 0 && b != 0 {
        if c != 0 {
                d = "true"
        } else {
                d = "false"
        }
} else {
        d = "false"
}
fmt.Println("Example bool is: ", d)

Der ternäre Ausdruck ist nur ein Sonderfall der if-Anweisung. Es lohnt sich nicht, für einen einfachen Spezialfall eine neue Syntax hinzuzufügen.

Ja, bitte, ja! Ich liebe Go und es konzentriert sich auf Lesbarkeit, aber es hat seinen Preis als sehr ausführlicher Code.
Ich bin fest davon überzeugt, dass der ternäre Operator die „Beschreibbarkeit“ verbessern wird, ohne die Lesbarkeit zu beeinträchtigen. Es wird den Code von Go nur ein wenig eleganter und bequemer machen.

Apropos Mehrdeutigkeit und andere Codierungsprobleme: Ich würde sagen, dass Entwickler mit schlechten Codierungspraktiken sowieso ohne ternären Operator schlechten Code schreiben werden.

@ziflex IMHO besteht die beste Codierungspraxis zur Vermeidung von Mehrdeutigkeiten darin, selbst in einer Sprache mit ternärem Ausdruck KEINEN ternären Ausdruck zu verwenden.

Es gibt Fallen, die Sie vermeiden müssen, also müssen Sie Programmierpraktiken wie lernen

  1. verschachteln Sie es nicht.
  2. Verwenden Sie es nur in einem wirklich einfachen Fall.
  3. Wenn die Logik komplex wird, schreiben Sie sie in if-else-Form um.
    ...

Diese Fallen bringen dich nach oben.

@DongchengWang Einige dieser Praktiken können leicht auf einfache „Wenn“-Anweisungen angewendet werden.

Viele Antwortende sagen, dass Ternary ersetzbar ist und nichts Neues bringt.

Aber gleichzeitig sehe ich, wie viele Leute „if err := mayError(); err != nil {}“-Konstruktion, die auch mit einfachen „if“-Anweisungen leicht umgeschrieben werden kann. Aber aus irgendeinem Grund beschwert sich niemand wirklich darüber. Warum? Weil es bequem ist. Und wahrscheinlich, weil es von Anfang an in der Sprache war.

Der einzige Grund, warum wir darüber streiten, ist, weil der Operator nicht von Anfang an da war.

Persönlich gab es einige Fälle, in denen ein ternärer Ausdruck zu einem sauberer aussehenden, weniger verschachtelten Code geführt hätte. Allerdings nur wenige, also bin ich nicht damit verheiratet ...

Um die zusätzliche Komplexität der Syntax durch die Verwendung der mehr oder weniger standardmäßigen ?: -Zeichen zu vermeiden, wie wäre es mit der Wiederverwendung bestehender Sprachschlüsselwörter wie im Fall der for -Schleife wie folgt?

port := 80 if production else 8080

Es erlaubt Ihnen immer noch, es zu verketten und zu missbrauchen, aber nur so viel, wie Sie es mit einem traditionellen if/else -Block könnten ...

Ich denke, Sie sollten immer noch über die Prinzipien nachdenken, warum diese Sprache geboren wurde: einfach, eine offensichtliche Art, Dinge zu tun, orthogonale Funktionen und Bibliotheken.

Ich denke, wir sind da bei etwa 70 %. Nicht alles ist perfekt.

Was ich bisher an Go mag, ist die Tatsache, dass es den Streit zwischen Teammitgliedern über die Art der Codierung, über den Codestil, den jeder von ihnen verwenden kann, verringert (erinnern Sie sich an verschiedene Versionen von PSRs in PHP?). Wir in unserem 7-köpfigen Team streiten nie über die Codes der anderen. Wir konzentrieren uns nur auf unser Ziel.

Nicht, dass ich den ternären Bedingungsoperator nicht mag, aber ich muss Einwände dagegen erheben, ihn und dergleichen zu Go hinzuzufügen, weil ich die Art der Codierung nicht mag, die zu einem unserer Argumente wird.

Unnötiger Zucker. Ich denke, es ist eine dieser Zeiten, in denen wir versuchen, etwas zu bringen, das "in einer anderen Sprache verwendet wurde". Fühlt sich nicht an.

Wie oben erwähnt, gibt es einen bestehenden FAQ-Eintrag, der erklärt, warum die Sprache keinen Bedingungsoperator hat. Das Thema hat keine starke Unterstützung. Das Hinzufügen einer neuen Funktion zur Sprache kann es nie einfacher machen. Sobald es zwei Möglichkeiten gibt, etwas zu tun ( if oder ?: ), muss jeder Programmierer oft entscheiden, welche Form er verwenden möchte, was nicht gut ist. Generell sehen wir hier keine neuen Argumente.

Daher ist dies ein wahrscheinlicher Rückgang . Einen Monat lang für abschließende Kommentare offen lassen.

Zu @ziflex bin ich mir nicht sicher, wie eine ausführliche Inline ist, wenn:

if bool := operation(); bool {}

unterscheidet sich stark von einem ternären Operator. Es ist ein Konstrukt, das ich nicht gerne aufgeben würde, aber es besteht die Möglichkeit, dass es unter der gleichen Komplexität eines eval ? a : b leidet wie:

func main() {
    if a := A(); !B(a) && !C(a) && D(C(a)) {
        fmt.Println("confused")
    }
}

func A() bool {
    return true
}

func B(in bool) bool {
    return !in
}

func C(in bool) bool {
    return in
}

func D(in bool) bool {
    return in
}

Dies dient nur zur Veranschaulichung, dass schlecht geschriebener Code in einer einzelnen Zeile so unlesbar werden kann wie einige der obigen Beispiele. Die Möglichkeit, eine Syntax zu missbrauchen, sollte meiner Meinung nach nicht Grund genug sein, um zu verhindern, dass der Sprache ein signifikant nutzbarer Operator hinzugefügt wird.

Das if-else-Formular erfüllt jedoch seine Aufgabe. Ich denke, eine kürzere Form ist nicht immer die klarere Form.

var a, b, c int
fmt.Println("Example bool is: ", a != 0 && b != 0 ? c != 0 ? "true" : "false" : "false")

Das ist ein schlechtes Beispiel, weil Sie Klammern weggelassen haben, wodurch Ihr Beispiel extrem verschleiert klingt, obwohl es verständlich sein könnte.

Ich denke wirklich
go var a, b, c int fmt.Println("Example bool is: ", (a != 0 && b != 0 ? (c != 0 ? "true" : "false") : "false"))

ist besser lesbar als

var a, b, c int
var d string
if a != 0 && b != 0 {
        if c != 0 {
                d = "true"
        } else {
                d = "false"
        }
} else {
        d = "false"
}
fmt.Println("Example bool is: ", d)

(Auch wenn Ihr Beispiel eigentlich noch einfacher sein könnte, aber ich nehme an, darum geht es nicht:)

go fmt.Println("Example bool is: ", (a != 0 && b != 0 && c != 0 ? "true" : "false"))

Obwohl ich gelegentlich eine Bedingung in anderen Ausdrücken oder Anweisungen haben möchte, habe ich fast immer das Gefühl, dass dies die Lesbarkeit beeinträchtigen würde.

Das einzige, was ich daran bedauere, ist das Fehlen einer Möglichkeit, eine bedingte Initialisierung zu haben, bei der beide Zweige keinen Nullwert haben würden. Ich weiß, dass der Compiler wahrscheinlich intelligent genug ist, um dies nicht verschwenderisch zu machen, aber mein Gefühl dafür, was die abstrakte Maschine tut, sagt mir, dass ich einen Wert auf Null setze und ihn dann sofort überschreibe. Das ist... wirklich ein ziemlich schwaches Argument.

FWIW, ich finde die ternäre Form der "Example bool"-Beispiele nicht besser lesbar, nicht zuletzt, weil sie auf meinem Display im Moment horizontales Scrollen erfordern, um überhaupt den vollständigen Ausdruck zu sehen. Selbst wenn ich das mache, muss ich viel öfter hin und her schauen, um herauszufinden, was es tut.

Die offensichtliche Antwort einiger Skriptsprachen ist, dass if-Anweisungen Ausdrücke sind, die zugewiesen werden können, und ich mag dieses Design für diese Sprachen wirklich sehr, aber ich glaube nicht, dass ich es für go so sehr mögen würde.

Ich nehme an, es gibt immer:

x := func() int {
    if a {
        return 1
    }
    return 2
}()

... aber wenn wir darüber nachdenken, wenn wir das rationalisieren könnten, wäre es für solche Umstände tatsächlich ziemlich brauchbar. Etwas, das uns ausdrücken lässt: "Diese Funktion ist eigentlich nur eine Notation, es besteht keine Notwendigkeit, tatsächlich Funktionscode zu generieren, wir wollen nur eine Möglichkeit, Rückgabeausdrücke in einem inneren Block zu verwenden" ...

Die Go-Sprache wurde für Einfachheit geboren. Warum willst du diese ausgefallenen Dinge tun? Sie haben das Gefühl, dass Sie ein paar Codezeilen geschrieben haben, aber es fügt dem Code mehr Komplexität und Verwirrung hinzu.
Also unterstütze ich nicht

Es ist nicht „schick“, es ist „einfach“, also passt es genau hinein. Es ist vertraut, weil wir es in vielen anderen Sprachen verwenden. Es ist praktisch, weil es sich um einen einzeiligen Ausdruck mit wenig Tipparbeit handelt. Es ist wichtig, es zu haben, weil es ein allgemeines Konstrukt ist, das wir oft verwenden würden.

Dann würde ich lieber ein Listenverständnis wie Python verwenden:
a if a>1 else b
Statt allerlei seltsamen Symbolen, genau wie bei Rust.
Ich würde lieber mehr Code schreiben, um es auszudrücken, als diese seltsamen Symbole zu verwenden, um den Code wegzulassen.
Der Code ist für Menschen zum Lesen.

Bitte fügen Sie keine neuen Grammatikfunktionen für eine Situation hinzu, die nicht häufig verwendet wird, da Sie die ursprüngliche Absicht von Go zerstören, nämlich einfach und leicht zu lesen.
Ich denke, dass viele Leute manchmal egoistisch sind, weil sie in bestimmten Situationen bequem sind oder weil sie von den Komfortfunktionen anderer Programmiersprachen verwöhnt sind, müssen Sie ihre Lieblingsfunktionen in Go hinzufügen.
Was ich sagen möchte ist, dass Go nicht Ihre Sprache ist, Go hat seinen eigenen Weg.
Obwohl Sie Ihre eigene Sprache erfinden können, können Sie.

@Yanwenjiepy Sieht so aus, als wärst du auch ein Go-Purist geworden, der meiner Meinung nach den Fortschritt behindert.

I would rather write more code to express it than to use these strange symbols
Es mag für Sie seltsam sein, aber nicht seltsame Symbole für die meisten von uns, die mit einer gängigen C-basierten Sprache vertraut sind; C, C++, C#, Java, JavaScript usw. Sie alle haben den ternären Ausdruck.

Please don't add new grammar functions for a situation that is not commonly used
Ternäre Bedingungsanweisungen sind tatsächlich sehr praktisch und werden häufig verwendet!

Nur um wählerisch zu sein, das ist kein "Listenverständnis". Ein Listenverständnis ist speziell so etwas wie [x for y in z] (ggf. plus Bedingungen). Die Verwendung von if/else in Ausdrücken ist eine andere Funktion.

Ich bin mit ternären Operatoren gut vertraut und habe die meiste Zeit meines Lebens Sprachen verwendet, die sie hatten, aber ungefähr 95% der Verwendungen, die ich in anderen Sprachen gesehen habe, würden meiner Meinung nach schlecht zu dem passen, was die Arbeit mit Go angenehm macht in. Go hat dazu tendiert, gewisse Arten von Informationsdichte zu vermeiden, wie z. Es braucht zu viel Platz, um zu durchdenken, was es tut.

Der Compiler ist einigermaßen schlau. Sie können einen Wert deklarieren, ihm bedingt zuweisen, ihn einmal verwenden und erwarten, dass der Compiler ungefähr so ​​​​gut arbeitet wie bei einem ternären Ausdruck.

@Yanwenjiepy Es sieht so aus, als wärst du auch ein Go-Purist geworden, was meiner Meinung nach den Fortschritt behindert.

I would rather write more code to express it than to use these strange symbols
Für die meisten von uns, die mit einer gängigen C-Sprache vertraut sind, mag dies eine seltsame, aber keine seltsame Notation sein; C, C++, C#, Java, JavaScript usw. Beide haben ternäre Ausdrücke.

Please don't add new grammar functions for a situation that is not commonly used
Ternäre bedingte Anweisungen sind tatsächlich sehr praktisch und werden häufig verwendet!
Vielleicht habe ich selbst ein ähnliches Gefühl. Vielleicht bin ich in anderen Fragen kein 'Go-Purist'. Das ist sehr verwirrend.

@seebs Ich kann diese Meinung sicherlich respektieren, aber für viele von uns, die aus anderen C-basierten Sprachen kommen, bedeutet "angenehm zu arbeiten" Produktivität durch Vertrautheit und Bequemlichkeit. Ich konnte nie verstehen, warum i++ in Go weniger angenehm/bequem ist als i = i + 1 , besonders wenn ein Postinkrement in Schleifen ok ist, zB for i := 0; i < 5; i++ {...} aber als Statement nicht ok ist! Zu viel Purismus sage ich! :)

Worüber redest du? i++ ist als Anweisung in Go durchaus zulässig. was nicht erlaubt ist, ist die Verwendung in einem _Ausdruck_, wo es sowohl auf einen Wert als auch auf einen Nebeneffekt ausgewertet wird.

https://play.golang.org/p/m_LbSbmT1Ar

Als jemand, der sich einigermaßen gut mit C auskennt, finde ich dennoch, dass ich ohne den ternären Operator gut auskomme, und mir gefällt der resultierende Code besser. Ich benutze es auch nicht mehr so ​​oft in C, genauso wie ich konsequenter geworden bin, Klammern in allen Blöcken zu verwenden, nicht nur in Blöcken mit mehr als einer Anweisung darin.

Ich meinte nicht i++ allein, ich meinte einen Ausdruck wie fmt.Printf("%d", i++) , was für einige von uns praktisch wäre.

Ja, es ist definitiv praktisch, aber es ist ziemlich eindeutig weniger wartbar. Leute machen Fehler damit, Leute missverstehen Code, der es benutzt. Es ist eine Quelle von Fehlern, und es bringt einfach nicht so viel Wert.

Ja, wenn ich x++ machen will, muss ich es als eigene Anweisung vor oder nach Printf machen. Das ist in der Tat ein Preis, überhaupt. Aber dafür bekomme ich:

  • Ich habe nicht plötzlich, dass x die falschen Werte bekommt, wenn ich einige der Printf-Aufrufe auskommentiere.
  • Änderungen an den Formatnachrichten brechen meine Programmlogik nicht.
  • Jemand anderes, der den Code überfliegt (oder ich ohne genug Kaffee), wird nicht einfach übersehen, dass das Inkrement dort drin ist.

Es ist ein Kompromiss, aber ich denke, es ist ein ziemlich guter. Ich verbringe einen Teil meiner Zeit damit, Programmierfragen von Anfängern zu beantworten, denn das ist ein Teil davon, wie wir gesündere Sprachgemeinschaften entwickeln. Ich verbringe viel weniger Zeit damit, Feinheiten in der Interpunktion im Go-Code der Leute zu rätseln als in ihrem C-Code, und sie haben viel weniger Probleme, die ausschließlich durch subtile Tippfehler verursacht werden.

Ich versichere Ihnen, dies ist kein Purismus, der von Leuten kommt, die C nicht verstehen oder schätzen. Es ist eine wohlüberlegte Entscheidung, dass diese Sprache einen großen Wert daraus zu ziehen scheint, einfach nicht so kompliziert zu sein, und das lässt uns mehr Raum dafür komplizierte Dinge mit unserer Logik zu tun, da wir nicht so viel von unserer Mühe aufwenden, den Code zu analysieren.

Ich höre Sie, aber ich bin von all dem nicht überzeugt. Folgendes funktioniert beispielsweise in Go und sollte laut Ihrer Argumentation die einzig zulässige Syntax sein:

    for i:=0; i<5; i=i+1 {
      fmt.Printf("%d\n", i)
    }

Aber auch die populärere/bekanntere Syntax ist erlaubt:

    for i:=0; i<5; i++ {
      fmt.Printf("%d\n", i)
    }

Warum denkst Du, das ist?

Mein Argument besagt nämlich nicht, dass nur das erste zulässig sein sollte. Mir gefällt der zweite besser, er ist einfacher und leichter zu lesen, weil der Inkrementoperator eine eigenständige Sache ist, kein Nebeneffekt .

Beachten Sie, dass Sie Folgendes nicht tun können:

i := 0
for i++ < 5 {
    ...
}

Weil Sie mit Go keine Zuweisungen oder Inkremente in Ausdrücke einfügen können. Und das mag manchmal eine Unannehmlichkeit sein, aber die Häufigkeit, mit der es nicht dazu führt, dass Menschen einen Ausdruck missverstehen und nicht erkennen, dass er Werte verändert, liegt im Grunde bei 100 %, was schön ist.

Sehen Sie, das ist mir zu puristisch :) Wie auch immer, mein Punkt ist, da sowohl i=i+1 als auch i++ in Schleifen erlaubt sind, sage ich, erlauben Sie auch eine ternäre Variation für diejenigen, die die einzeilige Bequemlichkeit bevorzugen , z.B

„Geh
Hafen := Produktion ? 80 : 8080

as well as the usual:

```Go
Port := 8080
if production {
    Port = 80
}

Wenn es um Einfachheit geht, denke ich, dass ersteres einfacher ist.

Wie wäre es mit:

Port := production++

oder

fmt.Printf("port: %d\n", production++)

Beide sind mit dem C-Idiom auch kürzer als in Go. Aber ich würde argumentieren, dass in beiden Fällen die Möglichkeit, dass diese Komplexität existiert, das gesamte Programm etwas schwerer verständlich macht – Sie müssen jetzt die ganze Zeit auf diese Effekte achten.

Auf einer grundlegenderen philosophischen Ebene: Das Problem ist, dass Ihre Lösung nicht nur für diejenigen ist, die diese "Bequemlichkeit" bevorzugen. Es wird auch allen anderen mit Gewalt aufgezwungen, für immer. Denn jeder muss den Code der anderen lesen . Die Leute können sich also nicht von einer Funktion wie dieser abmelden. Sie können nicht sagen "naja, das ist schwieriger für mich zu warten, also werde ich es nicht verwenden" und müssen sich nicht damit auseinandersetzen. Sie stecken damit fest, dass es Teil ihrer Welt ist. Wann immer sie Code lesen, an dem jeder andere hätte arbeiten können, müssen sie auf eine neue Reihe von Komplexitäten achten.

In der Praxis hat diese "Einfachheit" einen erheblichen Preis, da es nicht wirklich Einfachheit ist, sondern nur den Ausdruck verkürzt. Es ist wie das einzeilige klammerlose if ; Es scheint, als wäre es einfacher, aber dann brauchen Sie eine zweite Zeile und es besteht eine Wahrscheinlichkeit ungleich Null, dass Sie dann vergessen, die geschweiften Klammern hinzuzufügen, und ziemlich bald haben Sie mehr Zeit verloren, als Sie nur die geschweiften Klammern dort gesetzt hätten.

Ich weiß, was passiert, wenn du schreibst:

Port := production ? 80 : 8080

Ein paar Tage später:

Port := production ? 80 : test ? 4080 : 8080

Aber dann erkennt jemand, dass die beiden bools eine schlechte Wahl sind, und behebt das:

Port := mode == "production" ? 80 : mode == "test" ? 4080 : 8080

und weil es nur eine Zeile war und ?: verwendet wird, haben die Leute das Gefühl, dass es zusätzlicher Aufwand ist, es zu verlängern, und sie reparieren oder bereinigen es nicht. Und jetzt haben sie eine Investition darin, dass es so ist.

Und so landen Sie bei ?: Operationen, die 15 tief verschachtelt sind, was ich im tatsächlichen Code gesehen habe, der unbedingt Nachschlagetabellen hätte sein sollen.

Und so landen Sie bei ?: Operationen, die 15 tief verschachtelt sind, was ich in tatsächlichem Code gesehen habe, der unbedingt Nachschlagetabellen hätte sein sollen.

"if-else"-Operationen, die 15 tief verschachtelt sind, sollten jedoch auch unbedingt Nachschlagetabellen sein.

Oh, sicher.

Aber wenn Sie 15-fach verschachtelte if/else-Operationen haben und in eine Nachschlagetabelle konvertieren, haben Sie nicht das Gefühl, die "Einfachheit" der einzeiligen Lösung verloren zu haben.

Das Problem ist, dass Ihre Lösung nicht nur für diejenigen ist, die diese "Bequemlichkeit" bevorzugen. Es wird auch allen anderen mit Gewalt aufgezwungen, für immer

Ich könnte nicht mehr widersprechen, denn die Wahrheit ist das Gegenteil! Es ist eigentlich Ihre puristische Sichtweise, die Ihre Vorgehensweise aufzwingt und meine Freiheit, eine Kurzfassung zu wählen, einschränkt . Wenn Sie es nicht verwenden möchten, ist das Ihre Wahl, aber schränken Sie meine Wahl nicht ein!

Wenn ich wählen kann, ein verkürztes a := "freedom" statt var a string = "freedom" zu schreiben, dann sollte ich die Freiheit und Bequemlichkeit einer ternären Zuweisung haben.

Go-Tools leisten hervorragende Arbeit bei der Standardisierung der Codeformatierung, und ich denke, das allein macht es ziemlich einfach, den Code anderer Leute zu lesen.

Das Fazit für mich ist, dass ich ternäre Aufgaben leichter zu lesen und zu verstehen finde, weil sie natürlicher ins Englische übersetzt werden. Ich glaube, das ist der Grund, warum es in vielen anderen Sprachen so beliebt ist. Für mich das:

port := production ? 80 : 8080

...übersetzt zu: "Ist das Produktion? Wenn ja, ist Port 80 und wenn nein, ist Port 8080"
(eine einfache, unkomplizierte Einzelzuweisung, auch wenn sie verschachtelt ist)

port := 8080
if production {
    port = 80
}

Dies bedeutet übersetzt: "Port ist 8080 (Punkt) Oh, aber wenn dies die Produktion ist, ändern Sie den Port auf 80" (zweite Zuweisung).

Das zweite ist definitiv NICHT einfacher zu lesen für mich. Nie war.

Wenn es das ist? und : das stört die Leute, ich würde mich auch über eine alternative einzeilige Syntax freuen.

Dieses einzeilige Konstrukt funktioniert für nicht berechnete Anfangswerte. Eine Möglichkeit, dies auf berechnete Anfangswerte zu erweitern, wäre großartig.

v := a; if t { v = b }        // non-computed initial value

v := f(); else if t { v = b } // f() not evaluated where t==true

Leider zerstört _go fmt_ viele nützliche einzeilige Konstrukte. Aus diesem Grund verwende ich _go fmt_ nicht; teleskopierbarer lesbarer kompakter Code macht ihn weniger lesbar. Aber das ist tangential.

Diese Funktionalität ist ohne einen ternären Operator erreichbar, wenn Go 2 Generics hinzufügt

func ternary(type T)(cond bool, vTrue, vFalse T) T { 
    if cond { return vTrue } else { return vFalse }
}

Natürlich wäre es nicht schön, dies zu verwenden, besonders wenn es mehr als einen ternary -Aufruf gab.

Bei der Auswertung kann es sich um eine Optimierung auf Compiler-Ebene handeln.

Diese Funktionalität ist ohne einen ternären Operator erreichbar, wenn Go 2 Generics hinzufügt

func ternary(type T)(cond bool, vTrue, vFalse T) T { 
    if cond { return vTrue } else { return vFalse }
}

Natürlich wäre es nicht schön, dies zu verwenden, besonders wenn es mehr als einen ternary -Aufruf gab.

Bei der Auswertung kann es sich um eine Optimierung auf Compiler-Ebene handeln.

Brumm nein, vTrue und vFalse werden immer ausgewertet, meine ich

ternary(3>2, func1(), func2())

bewirkt den Aufruf von func1() und func2(). Kein Compiler könnte wissen, dass func2() nicht ausgewertet werden muss ... und er sollte das sowieso niemals annehmen, denn es ist ein grundlegendes Prinzip, dass bei einem Funktionsaufruf immer erwartet wird, dass die Argumente vor dem Aufruf der Funktion ausgewertet werden selbst. Wenn func2() zusätzlich zum Zurückgeben eines Werts Dinge tut, wollen wir, dass diese Dinge erledigt werden, sonst wäre es sehr unvorhersehbar und schwer zu verstehen.

(Im Gegensatz zu einem echten ternären Operator, bei dem der Wert von false grundsätzlich nicht ausgewertet werden soll.)
```

Diese Funktionalität ist ohne einen ternären Operator erreichbar, wenn Go 2 Generics hinzufügt

func ternary(type T)(cond bool, vTrue, vFalse T) T { 
    if cond { return vTrue } else { return vFalse }
}

Natürlich wäre es nicht schön, dies zu verwenden, besonders wenn es mehr als einen ternary -Aufruf gab.
Bei der Auswertung kann es sich um eine Optimierung auf Compiler-Ebene handeln.

Brumm nein, vTrue und vFalse werden immer ausgewertet, meine ich

ternary(3>2, func1(), func2())

bewirkt den Aufruf von func1() und func2(). Kein Compiler könnte wissen, dass func2() nicht ausgewertet werden muss ... und er sollte das sowieso niemals annehmen, denn es ist ein grundlegendes Prinzip, dass bei einem Funktionsaufruf immer erwartet wird, dass die Argumente vor dem Aufruf der Funktion ausgewertet werden selbst. Wenn func2() zusätzlich zum Zurückgeben eines Werts Dinge tut, wollen wir, dass diese Dinge erledigt werden, sonst wäre es sehr unvorhersehbar und schwer zu verstehen.

(Im Gegensatz zu einem echten ternären Operator, bei dem der Wert von false grundsätzlich nicht ausgewertet werden soll.)

Dann würde die Signatur so aussehen:

func ternary(type T)(cond bool, vTrueFunc, vFalseFunc func() T) T { 
    if cond { return vTrueFunc() } else { return vFalseFunc() }
}

Ich muss aber zugeben, diese Implementierung ist eine ganze Menge hässlich :(

Es gab zusätzliche Kommentare, da wir dies als wahrscheinlichen Rückgang erklärten (https://github.com/golang/go/issues/33171#issuecomment-525486967), aber soweit wir das beurteilen können, sagte keiner von ihnen etwas wesentlich Neues. Wir stimmen zu, dass es Fälle gibt, in denen die ?: -Syntax praktisch wäre, aber insgesamt scheint es sich nicht zu lohnen, sie der Sprache hinzuzufügen.

-- für @golang/proposal-review

Die Entscheidung basiert also auf „ erscheint nicht der Ergänzung wert“?
Ich bin überhaupt nicht überrascht ... Ternäre Ausdrücke würden die "Reinheit" der Sprache zerstören, oder?

Sprachänderungen sind immer ein Kosten-Nutzen-Kompromiss. Eine eindeutige Antwort gibt es selten.

Es gibt keine einfache Erklärung für das Fehlen einer ternären Operatorperiode.

Oberflächlich betrachtet ist die Weigerung, dieses grundlegende Merkmal zu implementieren, gleichbedeutend mit dem Argument, dass Fahrräder gefährlich sein können, wenn sie schnell sind, und als Ergebnis der Weigerung, ein Fahrrad mit hohen Gängen herzustellen. Einige werden vielleicht in die Konversation darüber verwickelt, ob die Spracharchitekten von Go richtig oder falsch liegen, aber ich würde es vorziehen, eine Abstraktionsebene zu erreichen und zu überlegen, ob Sprachen Feature-Bedenken mit Bedenken hinsichtlich der Wartbarkeit koppeln sollten:

Wenn Merkmal X missbraucht werden und zu einem Rattennest von Code führen könnte, ist das ein ausreichender Grund dafür, Merkmal X aus der Sprache auszuschließen?

Ich würde argumentieren, dass dies der Fall sein kann, aber nicht von selbst: Es sollte gegen Bedarf und Schwierigkeit abgewogen werden. Wenn eine Funktion sehr gefragt und einfach zu implementieren ist, wäre es besser, die Bedenken zu entkoppeln, indem man die Funktion implementiert und eine Möglichkeit bietet, sie zu verbieten – und sie sogar standardmäßig zu verbieten.

Wenn die Nachfrage hoch genug ist, sind sogar Schwierigkeiten ein schlechter Grund, sie abzulehnen. Betrachten Sie die class -Syntax in Javascript (ES2015): Die Architekten der Sprache wollten das Feature wirklich nicht hinzufügen, und es war tatsächlich ziemlich viel Arbeit, die Syntax hinzuzufügen, aber die Nachfrage war unglaublich hoch. Was haben Sie gemacht? Sie fügten die Syntax hinzu, wohl wissend, dass jede Organisation, die diese Funktion nicht wollte, die Syntax auf Linting-Ebene leicht verbieten konnte.

Dies ist angesichts der Nachfrage die geeignete Auflösung für den ternären Operator. Es ist angemessen, diese Bedenken zu entkoppeln, und sie auf eine besser konfigurierbare Weise zu lösen, wäre am sinnvollsten. Dasselbe sollte für Dinge wie "unused variable"-Fehler passieren, die Linting-Bedenken zu "Stop-the-Presses, Sie müssen diese eine Sache beheben, bevor das Programm läuft"-Krisen machen. (Ja, ich weiß, es gibt eine _ -Lösung, aber es ist immer noch so, dass dies konfigurierbar sein sollte.)

Es ist ein Fehler zu glauben, dass eine Sprache das Produkt einer kleinen Anzahl von Architekten sein sollte, die es besser wissen, ohne eine tiefe Verbindung zu denen zu haben, die die Sprache tatsächlich verwenden. Der Ruf nach Daten, um den Architekten der Sprache das Gegenteil zu beweisen, ist bewundernswert, aber eine solche Analyse ist unnötig. Schauen Sie sich nur die Größe dieses Threads an: Es gibt Nachfrage.

Leider führt das Ignorieren der Nachfrage zu konkurrierenden Produkten: In diesem Fall werden Sprachen auf diese Weise gegabelt. Willst du gegabelt werden? (Um es klar zu sagen: Dies ist eine Vorhersage, keine Drohung.
Ich forke definitiv keine Sprache.)

@dash Dieses Problem ist geschlossen, und ich werde es nicht bestreiten, aber ich möchte korrigieren, was ich für eine falsche Darstellung halte. Sie implizieren, dass Go eine Sprache ist, die "... das Produkt einer kleinen Anzahl von Architekten ist, die es besser wissen _ohne eine tiefe Verbindung zu denen, die die Sprache tatsächlich verwenden_". Dies ist sicherlich nicht wahr. Jeder im Go-Team und sicherlich die "Architekten" schreiben jeden Tag Go-Code und haben seit 2007 eine beträchtliche Menge davon geschrieben. Wir interagieren auch fast täglich mit anderen Go-Benutzern. Wir haben absolut eine tiefe Verbindung zu denen, die die Sprache tatsächlich verwenden, das sind wir – neben vielen anderen.

Ich gehöre nicht zu den Architekten, und ich verwende die Sprache häufig, und ich stoße regelmäßig auf Situationen, in denen ich mit ziemlicher Sicherheit einen ternären Operator verwenden würde, wenn er verfügbar wäre. Und dann lese ich später meinen Code und denke darüber nach und bin froh, dass er nicht da ist. YMMV.

Ich glaube nicht, dass es mein Leben als Entwickler leichter machen würde, Dinge wie diese oder die nicht verwendeten Variablenwarnungen "konfigurierbar" zu machen; Ich denke, es würde mein Leben als Entwickler schwieriger machen.

Ich bin auch keiner der Architekten, und ich benutze die Sprache auch stark, und ich stoße regelmäßig auf Situationen, in denen ich mit ziemlicher Sicherheit einen ternären Operator verwenden würde, wenn er verfügbar wäre. Und dann lese ich später meinen Code und verfluche die wenigen Leute, die uns dieses nützliche Feature verweigern!

Auch hier, ich benutze Go jeden Tag und würde es jeden Tag brauchen und ich bin überzeugt, dass es meinen Code klarer und noch robuster machen würde.

Übrigens im Vorschlag von "FAQ-Antwort umformulieren"

Verwendung eines ternären Operators anstelle einer bedingten Anweisung (nicht eines Ausdrucks) für die Kürze;

"Kürze" wird erwähnt, als ob es eine schlechte Sache wäre. Kürze hilft der Lesbarkeit. Die ganze Idee eines lesbaren Codes ist, dass er "direkt auf den Punkt" dessen ist, was er tatsächlich tut. Nicht wie 8080 oder -1 auf den Port und dann 80 später im Code, weil dies die Produktion ist.

Ich denke, dass es jetzt kaum eine Chance gibt, dass Go einen ternären Operator bekommt, nicht nur, weil das Go-Team konsequent dagegen argumentiert hat, sondern weil (nach der Emoji-Abstimmung zu urteilen) auch rund 60 % der Community dagegen sind.

Wenn Go jedoch irgendwann Generika bekommt, sollte das Team meiner Meinung nach ernsthaft erwägen, der Standardbibliothek eine ternäre Funktion hinzuzufügen, ungeachtet dessen, dass es keine Kurzschlüsse geben wird, außer möglicherweise durch Compiler-Optimierung.

Wenn sie dies nicht tun, werden die 40%, die für eine Art Termary-Operator / -Funktion sind (mich eingeschlossen), sofort ihre eigenen schreiben. Dies führt zu einem Lesbarkeits- und Wartungsalptraum, da unterschiedliche Namen gewählt werden (Cond, Iff, Iif, Pick, Choose, Tern usw.) und sie in Paketen mit unterschiedlichen Namen enthalten sind.

Wenn es stattdessen zur Standardbibliothek hinzugefügt wird, wird diese Fragmentierung nicht auftreten, da jeder, der dafür ist, die Standardversion verwenden wird und diejenigen, die es nicht mögen, wissen, was es tut.

func ifThen(condition bool, ifTrue,ifelse interface{}) interface{}{
wenn Bedingung {
Rückgabe wenn wahr
} anders {
sonst zurückgeben
}
}

Ich habe das Gefühl, dass diese Diskussion über den ternären Operator in einigen Fällen auf eine "Lösung für ein anderes Problem" hinausläuft.

Das Fehlen von Standardwerten in Funktionen führt dazu, dass Leute Code wie folgt schreiben:

if elementType == "" {
    elementType = "Whatever"
}
//  times X ...

mit Leuten, die dies einfach als:

elementType = elementType == "" ? "Whatever" : elementType
// times X ...

Oder

func DoDesign( elementType string = "Whatever" )

Ein ternärer Operator versucht also, ein Problem zu lösen, das mit einem anderen Problem zusammenhängt. Während die Standardversion von Go tatsächlich besser lesbar ist, wird sie weniger lesbar, wenn Sie es mit 4 oder 5 davon hintereinander zu tun haben.

Man muss sich auch fragen, ob der Lesbarkeit gedient ist, wenn Leute anfangen, mehr und mehr ihre eigenen "Lösungen" zu bauen, wie @ArnoldoR zeigt. Eines der Probleme, die Javascript plagen, ist die Zunahme von „Lösungen“ für fehlende Funktionalität, was dazu führte, dass einige Projekte links und rechts NPM-Pakete importierten. Beliebte Pakete wie SqlX sind eher ein Zeichen für fehlende Funktionen in Go.

Lesbarkeit ist das eine. Aber manchmal müssen 20 Zeilen geschrieben werden, die mehr oder weniger in 5 Zeilen enthalten sein können. Es häuft sich bei jedem Projekt.

Wenn das Problem darin besteht, dass Ternary missbraucht werden kann, um unlesbaren Code zu erstellen, insbesondere verschachtelte ternäre Operatoren, dann legen Sie eine Grenze fest. Ich denke, dass die meisten Leute in diesem Thema kein Problem haben werden, wenn ein ternärer Operator nur auf "eine Ebene" beschränkt ist und der Compiler Sie von Deep-Level-Operatoren abhält.

Wir wissen, dass die Leute Generika sowieso verdammt missbrauchen werden, um sie zu implementieren. Warum also nicht eine offizielle Version bereitstellen, dann können Sie den Missbrauch einschränken. Aber diese wilden Funktionen, wie wir oben sehen, werden mit der Zeit immer beliebter, wie wir in der Javascript-Community gesehen haben. Und wenn der Geist die Flasche verlässt, gibt es keine Kontrolle mehr.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen