Vorwort: Ohne zu argumentieren, dass dies if else
der richtige Weg ist, können wir immer noch mit sprachfähigen Konstrukten spielen und Freude daran haben.
Das folgende If
Konstrukt ist in meiner github.com/icza/gox
Bibliothek mit vielen anderen Methoden verfügbar , nämlich dem builtinx.If
Typ.
Mit Go können Methoden an benutzerdefinierte Typen angehängt werden , einschließlich primitiver Typen wie z bool
. Wir können einen benutzerdefinierten Typ mit bool
dem zugrunde liegenden Typ erstellen und dann mit einer einfachen Typkonvertierung für die Bedingung auf seine Methoden zugreifen. Methoden, die Operanden empfangen und aus diesen auswählen.
Etwas wie das:
type If bool
func (c If) Int(a, b int) int {
if c {
return a
}
return b
}
Wie können wir es benutzen?
i := If(condition).Int(val1, val2) // Short variable declaration, i is of type int
|-----------| \
type conversion \---method call
Zum Beispiel ein ternäres Tun max()
:
i := If(a > b).Int(a, b)
Ein ternäres Tun abs()
:
i := If(a >= 0).Int(a, -a)
Das sieht cool aus, ist einfach, elegant und effizient (es ist auch zum Inlining geeignet ).
Ein Nachteil im Vergleich zu einem "echten" ternären Operator: Er wertet immer alle Operanden aus.
Um eine verzögerte Auswertung zu erreichen, besteht die einzige Möglichkeit darin, Funktionen (entweder deklarierte Funktionen oder Methoden oder Funktionsliterale ) zu verwenden, die nur bei Bedarf aufgerufen werden:
func (c If) Fint(fa, fb func() int) int {
if c {
return fa()
}
return fb()
}
Verwenden Sie es: Nehmen wir an, wir haben diese Funktionen zu berechnen a
und b
:
func calca() int { return 3 }
func calcb() int { return 4 }
Dann:
i := If(someCondition).Fint(calca, calcb)
Zum Beispiel ist die Bedingung aktuelles Jahr> 2020:
i := If(time.Now().Year() > 2020).Fint(calca, calcb)
Wenn wir Funktionsliterale verwenden möchten:
i := If(time.Now().Year() > 2020).Fint(
func() int { return 3 },
func() int { return 4 },
)
Schlussbemerkung: Wenn Sie Funktionen mit unterschiedlichen Signaturen hätten, könnten Sie diese hier nicht verwenden. In diesem Fall können Sie ein Funktionsliteral mit übereinstimmender Signatur verwenden, um sie weiterhin anwendbar zu machen.
Zum Beispiel, wenn calca()
und calcb()
neben dem Rückgabewert auch Parameter vorhanden wären:
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 .