162

Please see https://golangdocs.com/ternary-operator-in-golang as pointed by @accdias (see comments)

Can I write a simple if-else statement with variable assignment in go (golang) as I would do in php? For example:

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

Currently I have to use the following:

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

Sorry I cannot remember the name if this control statement and I couldn't find the info in-site or through google search. :/

Lino
  • 19,604
  • 6
  • 47
  • 65
thoroc
  • 3,291
  • 2
  • 27
  • 34
  • 6
    Its called a ternary operator ... and no, Go doesn't have one. – Simon Whitehead Oct 24 '14 at 10:11
  • 6
    I believe the word you're looking for is "ternary" – BenjaminRH Oct 24 '14 at 10:11
  • 12
    Just to clarify, a ternary operator is any operator of arity 3, that is any operator that binds 3 sub-expressions. C happens to have only one such operator. That's why it is usually called the ternary operator. Its real name is "conditional operator", though. – thwd Oct 24 '14 at 10:41
  • Please, take a look at [The ternary operator in GoLang](https://golangdocs.com/ternary-operator-in-golang). – accdias Jun 30 '21 at 14:01

12 Answers12

212

As the comments mentioned, Go doesn't support ternary one liners. The shortest form I can think of is this:

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

But please don't do that, it's not worth it and will only confuse people who read your code.

Not_a_Golfer
  • 47,012
  • 14
  • 126
  • 92
  • 112
    @thoroc I'd actually probably avoid that in real life, as it is non intuitive IMHO, it's not worth saving 2 lines for less readability. – Not_a_Golfer Oct 24 '14 at 11:09
  • 18
    @thoroc, please listen to what Not_a_Golfer said. You should strive to write maintainable software, not *show yourself off.* Neat tricks are neat but the next guy reading your code (including you in a couple of months/years) won't appreciate them. – kostix Oct 24 '14 at 18:07
  • 4
    It depends, as far as readability. I think this is more readable, but like anything else, it can be abused. If you need to declare a variable that isn't needed outside of the if block, then I think this is a winner. – arjabbar Jun 09 '15 at 15:50
  • @Not_a_Golfer it's not only readability by symmetry, the structural contrast to the intent is also in the compiled code, sometimes even with extra cost for a redundant initialization. – Wolf Dec 13 '16 at 07:42
  • Agree with others, I'd really avoid this notation; my first thought when reading this would be that the intent was to do a comparison between `c` and `b`; something like `if c == b; (and) a > b (then) a = c` – thaJeztah Dec 17 '16 at 15:39
  • 7
    Oh, joy, look at how much Go gained by not having a ternary operator. Aside from the readability comments made, you've changed a lazily-evaluated construct where only one branch is ever run to one where the first is always run and the second may be run in addition. – itsbruce Apr 01 '17 at 07:57
  • I'm wondering if that can be written as `if (c = b) <= a { c = a }` and achieve the same effect. – accdias Jun 30 '21 at 14:07
  • 2
    @accdias no, it doesn't work in Go. – Not_a_Golfer Jun 30 '21 at 20:58
47

As the others mentioned, Go does not support ternary one-liners. However, I wrote a utility function that could help you achieve what you want.

// 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
}

Here are some test cases to show how you can use it

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)
}

For fun, I wrote more useful utility functions such as:

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

If you would like to use any of these, you can find them here https://github.com/shomali11/util

Raed Shomali
  • 1,385
  • 15
  • 7
  • I prefer `If(c bool).Then(a interface{}, b interface{})` from [this answer](https://stackoverflow.com/a/59375088/1713660), it looks more idiomatic for me – vladkras Dec 08 '20 at 11:47
  • 1
    What about: ```If(c bool).Then(a interface{}).Else(b interface{})``` Can drop the else if only initial value required. even like this: ```If(c bool).Then(a interface{}).Default(b interface{})``` – Cyberience Dec 16 '20 at 08:35
  • Lovely! thanks for sharing. – earizon Aug 17 '21 at 15:13
37

I often use the following:

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

basically the same as @Not_a_Golfer's but using type inference.

xoyuz
  • 487
  • 5
  • 4
  • 9
    With the same shortcoming: you complicate the understanding when using an asymmetric solution for an obviously symmetric requirement. – Wolf Dec 13 '16 at 07:48
  • 3
    And the same shortcoming of turning what should be a lazily-evaluated construct where only one of two branches will ever be used into one where one will always be evaluated, sometimes both (in which case the first evaluation was redundant) – itsbruce Apr 01 '17 at 08:01
  • 1
    Depending on the use-case, this still might be very useful. E.g. `listeningPath := "production.some.com"; if DEBUG { listeningPath := "development.some.com" }` Same speed as ternary for production, and imho pretty good readability. – Levite Nov 09 '17 at 11:42
  • I usually cry when waste intentionally CPU cycle. – alessiosavi Mar 03 '20 at 22:17
26

Thanks for pointing toward the correct answer.

I have just checked the Golang FAQ (duh) and it clearly states, this is not available in the language:

Does Go have the ?: operator?

There is no ternary form in Go. You may use the following to achieve the same result:

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

additional info found that might be of interest on the subject:

thoroc
  • 3,291
  • 2
  • 27
  • 34
  • it's also possible in one line: `var c int; if a > b { c = a } else { c = b }`? But I'd suggest keeping it in 5 lines to form a light block for the reader's recreation ;) – Wolf Dec 13 '16 at 07:38
12

One possible way to do this in just one line by using a map, simple I am checking whether a > b if it is true I am assigning c to a otherwise b

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

However, this looks amazing but in some cases it might NOT be the perfect solution because of evaluation order. For example, if I am checking whether an object is not nil get some property out of it, look at the following code snippet which will panic in case of myObj 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}

Because map will be created and built first before evaluating the condition so in case of myObj = nil this will simply panic.

Not to forget to mention that you can still do the conditions in just one simple line, check the following:

var c int
...
if a > b { c = a } else { c = b}
Muhammad Soliman
  • 21,644
  • 6
  • 109
  • 75
  • 1
    Just think of all that effort you wasted with this approach. You allocated the memory, initialized a map, added two entries to it, fully evaluating both, then hashed the lookup value, looked up and then let the map be collected by GC. Yes, it's a one-liner, but does it worth it? It's even worse than doing `Optional.ofNullable(x).ifPresent(...)` in Java. – Alexey Nezhdanov Aug 08 '21 at 04:02
  • I'd not use this but I like the fact that it is doable. – Anticro Jul 25 '23 at 14:41
4

A very similar construction is available in the language

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

*

i.e.

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

Use lambda function instead of ternary operator

Example 1

to give the max int

package main

func main() {

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

Example 2

Suppose you have this must(err error) function to handle errors and you want to use it when a condition isn't fulfilled. (enjoy at 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)
}
Alice Vixie
  • 422
  • 4
  • 10
2

Sometimes, I try to use anonymous function to achieve defining and assigning happen at the same line. like below:

a, b = 4, 8

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

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

Ron
  • 6,037
  • 4
  • 33
  • 52
2

Like user2680100 said, in Golang you can have the structure:

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

This is useful to shortcut some expressions that need error checking, or another kind of boolean checking, like:


var number int64
if v := os.Getenv("NUMBER"); v != "" {
   if number, err = strconv.ParseInt(v, 10, 64); err != nil {
       os.Exit(42)
   }
} else {
    os.Exit(1)
}

With this you can achieve something like (in C):

Sprite *buffer = get_sprite("foo.png");
Sprite *foo_sprite = (buffer != 0) ? buffer : donut_sprite

But is evident that this sugar in Golang have to be used with moderation, for me, personally, I like to use this sugar with max of one level of nesting, like:


var number int64
if v := os.Getenv("NUMBER"); v != "" {
    number, err = strconv.ParseInt(v, 10, 64)
    if err != nil {
        os.Exit(42)
    }
} else {
    os.Exit(1)
}

You can also implement ternary expressions with functions like func Ternary(b bool, a interface{}, b interface{}) { ... } but i don't like this approach, looks like a creation of a exception case in syntax, and creation of this "features", in my personal opinion, reduce the focus on that matters, that is algorithm and readability, but, the most important thing that makes me don't go for this way is that fact that this can bring a kind of overhead, and bring more cycles to in your program execution.

0

You can use a closure for this:

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() })
}

The only gripe I have with the closure syntax in Go is there is no alias for the default zero parameter zero return function, then it would be much nicer (think like how you declare map, array and slice literals with just a type name).

Or even the shorter version, as a commenter just suggested:

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)
}

You would still need to use a closure if you needed to give parameters to the functions. This could be obviated in the case of passing methods rather than just functions I think, where the parameters are the struct associated with the methods.

Louki Sumirniy
  • 106
  • 1
  • 1
  • 6
-1

As everyone else pointed out, there's no ternary operator in Go.

For your particular example though, if you want to use a single liner, you could use Max.

import "math"

...

c := math.Max(a, b)

Edson Medina
  • 9,862
  • 3
  • 40
  • 51
  • 1
    Looks like the people who voted down here did not think about the use-case. Thank you for your answer! – Anticro Jul 25 '23 at 14:46
-6

Ternary ? operator alternatives | golang if else one line You can’t write a short one-line conditional in Go language ; there is no ternary conditional operator. Read more about if..else of Golang