Vorwort: Ohne zu argumentieren, dass if else
der richtige Weg ist, können wir trotzdem mit Sprachkonstrukten spielen und Vergnügen finden.
Go 1.18 Generics Update: Go 1.18 fügt Generics-Unterstützung hinzu. Es ist jetzt möglich, eine generische If()
Funktion wie diese zu erstellen. Hinweis: Dies ist verfügbar in github.com/icza/gog
, als gog.If()
(Offenlegung: Ich bin der Autor).
func If[T any](cond bool, vtrue, vfalse T) T {
if cond {
return vtrue
}
return vfalse
}
Welche du verwenden kannst like this:
min := If(i > 0, i, 0)
Die Antwort vor 1.18 lautet:
Das folgende If
Konstrukt ist verfügbar in meiner github.com/icza/gox
Bibliothek mit vielen anderen Methoden, als der gox.If
Typ.
Go ermöglicht es, Methoden an beliebige benutzerdefinierte Typen anzuhängen, einschließlich primitiver Typen wie bool
. Wir können einen benutzerdefinierten Typ erstellen, der bool
als seinen unterliegenden Typ hat, und dann mit einer einfachen Typ Konvertierung auf die Bedingung haben wir Zugriff auf seine Methoden. Methoden, die die Operanden erhalten und auswählen.
So etwas wie dies:
type If bool
func (c If) Int(a, b int) int {
if c {
return a
}
return b
}
Wie können wir es nutzen?
i := If(condition).Int(val1, val2) // Kurze Variablendeklaration, i ist vom Typ int
|-----------| \
Typ-Konvertierung \---Methodenaufruf
Zum Beispiel ein Ternärer max()
machen:
i := If(a > b).Int(a, b)
Ein Ternärer abs()
machen:
i := If(a >= 0).Int(a, -a)
Dies sieht cool aus, es ist einfach, elegant und effizient (es ist auch für die Inline-Ausführung geeignet).
Ein Nachteil im Vergleich zu einem "echten" ternären Operator: Es werden immer alle Operanden ausgewertet.
Um eine verzögerte und nur bei Bedarf erfolgende Auswertung zu erreichen, ist die einzige Option die Verwendung von Funktionen (entweder deklarierte Funktionen oder Methoden, oder Funktionsliterale), die nur aufgerufen werden, wenn / wenn sie benötigt werden:
func (c If) Fint(fa, fb func() int) int {
if c {
return fa()
}
return fb()
}
Verwendung: Nehmen wir an, wir haben diese Funktionen zur Berechnung von a
und b
:
func calca() int { return 3 }
func calcb() int { return 4 }
Dann:
i := If(someCondition).Fint(calca, calcb)
Zum Beispiel die Bedingung, dass das aktuelle Jahr > 2020 ist:
i := If(time.Now().Year() > 2020).Fint(calca, calcb)
Wenn wir Funktionenliterale verwenden möchten:
i := If(time.Now().Year() > 2020).Fint(
func() int { return 3 },
func() int { return 4 },
)
Abschließende Anmerkung: Wenn Sie Funktionen mit unterschiedlichen Signaturen hätten, könnten Sie sie hier nicht verwenden. In diesem Fall können Sie ein Funktionsliteral mit passender Signatur verwenden, um sie dennoch anwendbar zu machen.
Zum Beispiel, wenn calca()
und calcb()
auch Parameter hätten (neben dem Rückgabewert):
func calca2(x int) int { return 3 }
func calcb2(x int) int { return 4 }
So könnten Sie sie verwenden:
i := If(time.Now().Year() > 2020).Fint(
func() int { return calca2(0) },
func() int { return calcb2(0) },
)
Probieren Sie diese Beispiele auf dem Go Playground aus.