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 can not remember the name if this control statement and I couldn't find the info through in-site and google search. :/
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
}
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:
I often use the following:
c := b
if a > b {
c = a
}
basically the same as @Not_a_Golfer's but using type inference.
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
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)
}
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}
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.
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
} ()
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)
}