ChatGPT解决这个技术问题 Extra ChatGPT

How to do one-liner if else statement? [duplicate]

This question already has answers here: What is the idiomatic Go equivalent of C's ternary operator? (13 answers) Closed last year.

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. :/

Its called a ternary operator ... and no, Go doesn't have one.
I believe the word you're looking for is "ternary"
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.
Please, take a look at The ternary operator in GoLang.

N
Not_a_Golfer

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.


@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.
@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.
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.
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.
@accdias no, it doesn't work in Go.
R
Raed Shomali

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


I prefer If(c bool).Then(a interface{}, b interface{}) from this answer, it looks more idiomatic for me
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{})
Lovely! thanks for sharing.
x
xoyuz

I often use the following:

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

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


With the same shortcoming: you complicate the understanding when using an asymmetric solution for an obviously symmetric requirement.
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)
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.
I usually cry when waste intentionally CPU cycle.
t
thoroc

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:

Rosetta Code for Conditional Structures in Go

Ternary Operator in Go experiment from this guy


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 ;)
M
Muhammad Soliman

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}

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.
u
user2680100

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

A
Alice Vixie

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

interesting approach, It might be useful in more complex cases. :)
R
Ron

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


This also might be useful in more complex cases +1.
I
Igor Fagundes

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.


L
Louki Sumirniy

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.


Shorter version doif(condition, dothis, dothat)
Yes, that would be even shorter, passing just the functions. One only has to have this function once in one utility library, and you can use it all through your code.
Why call the function instead of simply returning it?
E
Edson Medina

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)


L
Laxmikant Tiwari

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


Nothing new here. This has already been said in other answers, in a better way.
Furthermore, self promotion without any real use.