Wie mache ich einzeilige wenn sonst Aussage?


104

Kann ich eine einfache if-else-Anweisung mit variabler Zuweisung in go (golang) schreiben, wie ich es in PHP tun würde? Beispielsweise:

$var = ( $a > $b )? $a: $b;

Derzeit muss ich folgendes verwenden:

var c int
if a > b {
    c = a
} else {
    c = b
}

Entschuldigung, ich kann mich nicht an den Namen erinnern, wenn diese Steueranweisung und ich die Informationen nicht vor Ort oder über die Google-Suche finden konnten. : /


4
Es heißt ternärer Operator ... und nein, Go hat keinen.
Simon Whitehead

6
Ich glaube, das Wort, das Sie suchen, ist "ternär"
BenjaminRH


10
Zur Verdeutlichung ist ein ternärer Operator ein beliebiger Operator von Arity 3, dh ein beliebiger Operator, der 3 Unterausdrücke bindet. C hat zufällig nur einen solchen Operator. Deshalb wird es normalerweise als ternärer Operator bezeichnet. Sein richtiger Name ist jedoch "bedingter Operator".
thwd

Antworten:


131

Wie in den Kommentaren erwähnt, unterstützt Go keine ternären Einzeiler. Die kürzeste Form, die ich mir vorstellen kann, ist folgende:

var c int
if c = b; a > b {
    c = a
}

Aber bitte tun Sie das nicht, es lohnt sich nicht und wird nur Leute verwirren, die Ihren Code lesen.


83
@thoroc Ich würde das wahrscheinlich im wirklichen Leben vermeiden, da es meiner Meinung nach nicht intuitiv ist, es nicht wert ist, 2 Zeilen für weniger Lesbarkeit zu speichern.
Not_a_Golfer

14
@thoroc, bitte hör dir an, was Not_a_Golfer gesagt hat. Sie sollten sich bemühen, wartbare Software zu schreiben und sich nicht zu präsentieren . Ordentliche Tricks sind ordentlich, aber der nächste Typ, der Ihren Code liest (einschließlich Sie in ein paar Monaten / Jahren), wird sie nicht schätzen.
Kostix

3
Es kommt auf die Lesbarkeit an. Ich denke, das ist besser lesbar, aber wie alles andere kann es missbraucht werden. Wenn Sie eine Variable deklarieren müssen, die außerhalb des if-Blocks nicht benötigt wird, ist dies meiner Meinung nach ein Gewinner.
Arjabbar

@Not_a_Golfer Es ist nicht nur Lesbarkeit durch Symmetrie, der strukturelle Kontrast zur Absicht liegt auch im kompilierten Code, manchmal sogar mit zusätzlichen Kosten für eine redundante Initialisierung.
Wolf

5
Oh, Freude, schau dir an, wie viel Go gewonnen hat, wenn du keinen ternären Operator hast. Abgesehen von den Lesbarkeitskommentaren haben Sie ein träge ausgewertetes Konstrukt geändert, bei dem immer nur ein Zweig ausgeführt wird, in einen, bei dem der erste immer ausgeführt wird und der zweite möglicherweise zusätzlich ausgeführt wird.
itsbruce

29

Ich benutze oft Folgendes:

c := b
if a > b {
    c = a
}

Im Grunde das gleiche wie bei @ Not_a_Golfer, jedoch mit Typinferenz .


3
Mit dem gleichen Nachteil: Sie erschweren das Verständnis, wenn Sie eine asymmetrische Lösung für eine offensichtlich symmetrische Anforderung verwenden.
Wolf

2
Und das gleiche Manko beim Verwandeln eines träge bewerteten Konstrukts, bei dem immer nur einer von zwei Zweigen verwendet wird, in einen, bei dem immer einer bewertet wird, manchmal beide (in diesem Fall war die erste Bewertung überflüssig)
itsbruce

1
Je nach Anwendungsfall kann dies dennoch sehr nützlich sein. ZB listeningPath := "production.some.com"; if DEBUG { listeningPath := "development.some.com" }Gleiche Geschwindigkeit wie ternär für die Produktion und imho ziemlich gute Lesbarkeit.
Levite

Ich weine normalerweise, wenn absichtlich CPU-Zyklus verschwendet wird.
Alessiosavi

27

Wie die anderen erwähnt, Gounterstützt keine ternären Einzeiler. Ich habe jedoch eine Dienstprogrammfunktion geschrieben, mit der Sie das erreichen können, was Sie möchten.

// IfThenElse evaluates a condition, if true returns the first parameter otherwise the second
func IfThenElse(condition bool, a interface{}, b interface{}) interface{} {
    if condition {
        return a
    }
    return b
}

Hier sind einige Testfälle, um zu zeigen, wie Sie es verwenden können

func TestIfThenElse(t *testing.T) {
    assert.Equal(t, IfThenElse(1 == 1, "Yes", false), "Yes")
    assert.Equal(t, IfThenElse(1 != 1, nil, 1), 1)
    assert.Equal(t, IfThenElse(1 < 2, nil, "No"), nil)
}

Zum Spaß habe ich weitere nützliche Dienstprogrammfunktionen geschrieben, wie zum Beispiel:

IfThen(1 == 1, "Yes") // "Yes"
IfThen(1 != 1, "Woo") // nil
IfThen(1 < 2, "Less") // "Less"

IfThenElse(1 == 1, "Yes", false) // "Yes"
IfThenElse(1 != 1, nil, 1)       // 1
IfThenElse(1 < 2, nil, "No")     // nil

DefaultIfNil(nil, nil)  // nil
DefaultIfNil(nil, "")   // ""
DefaultIfNil("A", "B")  // "A"
DefaultIfNil(true, "B") // true
DefaultIfNil(1, false)  // 1

FirstNonNil(nil, nil)                // nil
FirstNonNil(nil, "")                 // ""
FirstNonNil("A", "B")                // "A"
FirstNonNil(true, "B")               // true
FirstNonNil(1, false)                // 1
FirstNonNil(nil, nil, nil, 10)       // 10
FirstNonNil(nil, nil, nil, nil, nil) // nil
FirstNonNil()                        // nil

Wenn Sie eines davon verwenden möchten, finden Sie es hier https://github.com/shomali11/util


12

Vielen Dank für den Hinweis auf die richtige Antwort.

Ich habe gerade die Golang-FAQ (duh) überprüft und es heißt eindeutig, dass dies nicht in der Sprache verfügbar ist:

Hat Go den Operator ?:?

Es gibt keine ternäre Form in Go. Sie können Folgendes verwenden, um das gleiche Ergebnis zu erzielen:

if expr {
    n = trueVal
} else {
    n = falseVal
}

Zusätzliche Informationen, die zu diesem Thema von Interesse sein könnten:


es ist auch in einer Zeile möglich : var c int; if a > b { c = a } else { c = b }? Aber ich würde vorschlagen, es in 5 Zeilen zu halten, um einen Lichtblock für die Erholung des Lesers zu bilden;)
Wolf

7

Eine Möglichkeit , dies zu tun in nur eine Zeile durch eine Karte verwenden, einfach ich bin Überprüfung , ob , a > bwenn es trueich bin Zuweisung czu asonstb

c := map[bool]int{true: a, false: b}[a > b]

Dies sieht zwar erstaunlich aus, ist jedoch in einigen Fällen aufgrund der Bewertungsreihenfolge möglicherweise NICHT die perfekte Lösung. Wenn ich zum Beispiel überprüfe, ob ein Objekt keine nilEigenschaft daraus erhält, sehen Sie sich das folgende Code-Snippet an, das panicim Falle vonmyObj equals nil

type MyStruct struct {
   field1 string
   field2 string 
}

var myObj *MyStruct
myObj = nil 

myField := map[bool]string{true: myObj.field1, false: "empty!"}[myObj != nil}

Da die Karte zuerst erstellt und erstellt wird, bevor der Zustand bewertet wird, kommt es in diesem Fall myObj = nileinfach zu einer Panik.

Um nicht zu vergessen zu erwähnen, dass Sie die Bedingungen immer noch in nur einer einfachen Zeile ausführen können, überprüfen Sie Folgendes:

var c int
...
if a > b { c = a } else { c = b}

4

Verwenden Sie die Lambda-Funktion anstelle des ternären Operators

Beispiel 1

um die max int zu geben

package main

func main() {

    println( func(a,b int) int {if a>b {return a} else {return b} }(1,2) )
}

Beispiel 2

Angenommen, Sie haben diese must(err error)Funktion zur Behandlung von Fehlern und möchten sie verwenden, wenn eine Bedingung nicht erfüllt ist. (viel Spaß unter https://play.golang.com/p/COXyo0qIslP )

package main

import (
    "errors"
    "log"
    "os"
)

// must is a little helper to handle errors. If passed error != nil, it simply panics.
func must(err error) {
    if err != nil {
        log.Println(err)
        panic(err)
    }
}

func main() {

    tmpDir := os.TempDir()
    // Make sure os.TempDir didn't return empty string
    // reusing my favourite `must` helper
    // Isn't that kinda creepy now though?
    must(func() error {
        var err error
        if len(tmpDir) > 0 {
            err = nil
        } else {
            err = errors.New("os.TempDir is empty")
        }
        return err
    }()) // Don't forget that empty parentheses to invoke the lambda.
    println("We happy with", tmpDir)
}

2
interessanter Ansatz, Es könnte in komplexeren Fällen nützlich sein. :)
Thoroc

1

Manchmal versuche ich, eine anonyme Funktion zu verwenden, um das Definieren und Zuweisen in derselben Zeile zu erreichen. Wie unten:

a, b = 4, 8

c := func() int {
    if a >b {
      return a
    } 
    return b
  } ()

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


0

Eine sehr ähnliche Konstruktion ist in der Sprache verfügbar

**if <statement>; <evaluation> {
   [statements ...]
} else {
   [statements ...]
}*

* *

dh

if path,err := os.Executable(); err != nil {
   log.Println(err)
} else {
   log.Println(path)
}

0

Sie können hierfür einen Verschluss verwenden:

func doif(b bool, f1, f2 func()) {
    switch{
    case b:
        f1()
    case !b:   
        f2()
    }
}

func dothis() { fmt.Println("Condition is true") }

func dothat() { fmt.Println("Condition is false") }

func main () {
    condition := true
    doif(condition, func() { dothis() }, func() { dothat() })
}

Der einzige Kritikpunkt, den ich an der Abschlusssyntax in Go habe, ist, dass es keinen Alias ​​für die Standard-Nullparameter-Rückgabefunktion gibt. Dann wäre es viel schöner (denken Sie daran, wie Sie Map-, Array- und Slice-Literale mit nur einem Typnamen deklarieren).

Oder sogar die kürzere Version, wie ein Kommentator gerade vorgeschlagen hat:

func doif(b bool, f1, f2 func()) {
    switch{
    case b:
        f1()
    case !b:   
        f2()
    }
}

func dothis() { fmt.Println("Condition is true") }

func dothat() { fmt.Println("Condition is false") }

func main () {
    condition := true
    doif(condition, dothis, dothat)
}

Sie müssten immer noch einen Abschluss verwenden, wenn Sie den Funktionen Parameter zuweisen müssten. Dies könnte vermieden werden, wenn Methoden übergeben werden und nicht nur Funktionen, von denen ich denke, dass die Parameter die mit den Methoden verknüpfte Struktur sind.


Kürzere Versiondoif(condition, dothis, dothat)
Vellotis

1
Ja, das wäre noch kürzer und würde nur die Funktionen übergeben. Diese Funktion muss nur einmal in einer Dienstprogrammbibliothek vorhanden sein, und Sie können sie über Ihren gesamten Code verwenden.
Louki Sumirniy
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.