In C / C ++ (und vielen Sprachen dieser Familie) verwendet ein allgemeines Idiom zum Deklarieren und Initialisieren einer Variablen in Abhängigkeit von einer Bedingung den ternären Bedingungsoperator:
int index = val > 0 ? val : -val
Go hat keinen bedingten Operator. Was ist die idiomatischste Methode, um denselben Code wie oben zu implementieren? Ich bin zu der folgenden Lösung gekommen, aber sie scheint ziemlich ausführlich zu sein
var index int
if val > 0 {
index = val
} else {
index = -val
}
Gibt es etwas besseres?
int index = -val + 2 * val * (val > 0);
Antworten:
Wie bereits erwähnt (und hoffentlich nicht überraschend),
if+else
ist die Verwendung in der Tat die idiomatische Methode , um in Go Bedingungen zu erfüllen.Zusätzlich zum vollständigen
var+if+else
Codeblock wird diese Schreibweise jedoch häufig verwendet:Wenn Sie einen Codeblock haben, der sich wiederholt, z. B. das Äquivalent von
int value = a <= b ? a : b
, können Sie eine Funktion erstellen, um ihn zu speichern:Der Compiler integriert solche einfachen Funktionen, sodass sie schnell, klarer und kürzer sind.
quelle
c := (map[bool]int{true: a, false: a - 1})[a > b]
ist meiner Meinung nach ein Beispiel für Verschleierung, auch wenn es funktioniert.if/else
der idiomatische Ansatz ist, könnte Golang möglicherweise in Betracht ziehen,if/else
Klauseln einen Wert zurückgeben zu lassen :x = if a {1} else {0}
. Go wäre keineswegs die einzige Sprache, die auf diese Weise funktioniert. Ein Mainstream-Beispiel ist Scala. Siehe: alvinalexander.com/scala/scala-ternary-operator-syntaxNo Go hat keinen ternären Operator. Die Verwendung der if / else-Syntax ist die idiomatische Methode.
quelle
if-else
Block weggelassen ? Und wer sagt, dass erif-else
nicht auf die gleiche Weise missbraucht wird? Ich greife dich nicht an, ich habe nur das Gefühl, dass die Entschuldigung der Designer nicht gültig genug istAngenommen, Sie haben den folgenden ternären Ausdruck (in C):
Der idiomatische Ansatz in Go wäre, einfach einen
if
Block zu verwenden:Dies entspricht jedoch möglicherweise nicht Ihren Anforderungen. In meinem Fall benötigte ich einen Inline-Ausdruck für eine Codegenerierungsvorlage.
Ich habe eine sofort ausgewertete anonyme Funktion verwendet:
Dies stellt sicher, dass nicht beide Zweige ebenfalls ausgewertet werden.
quelle
expr1 ? expr2 : expr3
. Wennexpr1
ausgewertet wirdtrue
,expr2
wird ausgewertet und ist das Ergebnis des Ausdrucks. Andernfallsexpr3
wird ausgewertet und als Ergebnis bereitgestellt. Dies stammt aus dem Abschnitt 2.11 der ANSI C-Programmiersprache von K & R. Die My Go-Lösung behält diese spezifische Semantik bei. @ Wolf Kannst du klarstellen, was du vorschlägst?Die ternäre Karte ist ohne Klammern leicht zu lesen:
quelle
simple and clear code is better than creative code.
Dies wird nicht übertreffen, wenn / sonst und erfordert Besetzung, funktioniert aber. Zu Ihrer Information:
BenchmarkAbsTernary-8 100000000 18,8 ns / op
BenchmarkAbsIfElse-8 2000000000 0,27 ns / op
quelle
Wenn alle Ihre Filialen Nebenwirkungen haben oder rechenintensiv sind, wäre das Folgende ein semantisch konservierendes Refactoring:
Normalerweise ohne Overhead (inline) und vor allem ohne Ihren Namespace mit Hilfsfunktionen zu überladen, die nur einmal verwendet werden (was die Lesbarkeit und Wartung beeinträchtigt). Live-Beispiel
Beachten Sie, wenn Sie Gustavos Ansatz naiv anwenden sollten :
Sie würden ein Programm mit einem anderen Verhalten erhalten ; falls das
val <= 0
Programm einen nicht positiven Wert drucken würde, während dies nicht der Fall sein sollte! (Analog dazu würden Sie, wenn Sie die Zweige umkehren, Overhead einführen, indem Sie unnötig eine langsame Funktion aufrufen.)quelle
abs
Funktion im ursprünglichen Code (na ja, würde ich ändern<=
zu<
). In Ihrem Beispiel sehe ich eine Initialisierung, die in einigen Fällen redundant ist und expansiv sein kann. Können Sie bitte klarstellen: Erklären Sie Ihre Idee etwas genauer?printPositiveAndReturn
nur für positive Zahlen aufgerufen wird. Umgekehrt werden die Nebenwirkungen des ersten Zweigs nicht rückgängig gemacht , wenn immer ein Zweig ausgeführt und dann der Wert durch Ausführen eines anderen Zweigs "festgelegt" wird .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 meinergithub.com/icza/gox
Bibliothek mit vielen anderen Methoden verfügbar , nämlich dembuiltinx.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 mitbool
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:
Wie können wir es benutzen?
Zum Beispiel ein ternäres Tun
max()
:Ein ternäres Tun
abs()
: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:
Verwenden Sie es: Nehmen wir an, wir haben diese Funktionen zu berechnen
a
undb
:Dann:
Zum Beispiel ist die Bedingung aktuelles Jahr> 2020:
Wenn wir Funktionsliterale verwenden möchten:
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()
undcalcb()
neben dem Rückgabewert auch Parameter vorhanden wären:So könnten Sie sie verwenden:
Probieren Sie diese Beispiele auf dem Go Playground aus .
quelle
Eolds Antwort ist interessant und kreativ, vielleicht sogar klug.
Es wird jedoch empfohlen, stattdessen Folgendes zu tun:
Ja, beide werden im Wesentlichen auf dieselbe Assembly kompiliert. Dieser Code ist jedoch viel besser lesbar als das Aufrufen einer anonymen Funktion, nur um einen Wert zurückzugeben, der überhaupt in die Variable geschrieben werden könnte.
Grundsätzlich ist einfacher und klarer Code besser als kreativer Code.
Darüber hinaus ist jeder Code, der ein Kartenliteral verwendet, keine gute Idee, da Karten in Go überhaupt nicht leichtgewichtig sind. Seit Go 1.3 ist die zufällige Iterationsreihenfolge für kleine Karten garantiert, und um dies zu erzwingen, ist die Speicherkapazität für kleine Karten erheblich geringer.
Das Erstellen und Entfernen zahlreicher kleiner Karten ist daher sowohl platz- als auch zeitaufwändig. Ich hatte einen Code, der eine kleine Karte verwendete (zwei oder drei Schlüssel sind wahrscheinlich, aber der übliche Anwendungsfall war nur ein Eintrag). Aber der Code war hundeschwach. Wir sprechen von mindestens 3 Größenordnungen langsamer als derselbe Code, der neu geschrieben wurde, um eine Dual-Slice-Key-Karte [index] => data [index] zu verwenden. Und wahrscheinlich war mehr. Einige Vorgänge, deren Ausführung zuvor einige Minuten dauerte, wurden in Millisekunden abgeschlossen. \
quelle
simple and clear code is better than creative code
- das gefällt mir sehr gut, aber ich werde im letzten Abschnitt etwas verwirrtdog slow
, vielleicht könnte das auch für andere verwirrend sein?m := map[string]interface{} { a: 42, b: "stuff" }
und dann in einer anderen Funktion, die es durchläuft:for key, val := range m { code here }
Nach dem Wechsel zu einem Zwei-Slice-System:keys = []string{ "a", "b" }, data = []interface{}{ 42, "stuff" }
und dann durchlaufen, als ob diefor i, key := range keys { val := data[i] ; code here }
Dinge 1000-fach beschleunigt worden wären.Einzeiler haben ihren Platz, obwohl sie von den Machern gemieden werden.
Dieser löst das Problem der verzögerten Bewertung, indem Sie optional Funktionen übergeben können, die bei Bedarf ausgewertet werden sollen:
Ausgabe
interface{}
, um die interne Cast-Operation zu erfüllen.c
.Die eigenständige Lösung hier ist ebenfalls nett, könnte aber für einige Anwendungen weniger klar sein.
quelle