Go has a common idiom that looks like this:
if val, err := func(); err != nil {
/* val and err are in scope */
...
}
/* val and err are no longer in scope */
using "short assignment". I'm certainly a fan. It feels similar to doing:
/* code not involving val */
{
int val;
if ((val = func()) == ERR_VALUE) {
/* Process the error */
}
/* Do something with val */
}
/* more code not involving val */
in C++. What trips me up is that, in the case where there is more than one variable in the first clause of the if, they have to have the same scope, i.e. you have to do either:
var err error
var val string
if val, err = func(); err != nil {
...
or
if val, err := func(); err != nil {
...
A very common use case would seem to be where you have a variable that you'd like to set in the first clause of the if, test for an error, and if there is none, continue with the rest of the program flow (and be able to use whatever values you assigned in executing the if). But, it seems to me, if you want to do that, you have to either:
Use a temporary variable, and then assign the persistent variable value inside an else:
var val
if tempval, err := func(); err != nil {
/* Process the error */
} else {
val = tempval
}
Declare the err variable with scope that extends past the if, as above.
The first option seems clunky - being forced to use an "else" clause just to make sure that the value doesn't fall out of scope - and the second throws away the advantages of limiting the scope of the variables. What idioms do more experienced Go programmers use for this (seemingly very common) situation?
The Go Programming Language Specification
If statements
"If" statements specify the conditional execution of two branches
according to the value of a boolean expression. If the expression
evaluates to true, the "if" branch is executed, otherwise, if present,
the "else" branch is executed.
IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] .
.
if x > max {
x = max
}
The expression may be preceded by a simple statement, which executes
before the expression is evaluated.
if x := f(); x < y {
return x
} else if x > z {
return z
} else {
return y
}
If you can't take advantage of the special form,
if val, err := fnc(); err != nil {
// ...
}
then use the regular form,
val, err := fnc()
if err != nil {
// ...
}
The regular form is the Go language necessary and usual form. The special form is a specialization, for convenience, of the regular form; it's not necessary. If the special form is more convenient to use than the regular form, use it. Otherwise, use the regular form.
Go is a block-structured programming language tracing it's ancestry back to Algol 60, C, Pascal, Modula 2, and Oberon.
The Go Programming Language Specification
Blocks
Declarations and scope
Therefore, you can write
x := false
{
x := true
if x {
fmt.Println(x)
}
}
fmt.Println(x)
or, equivalently, as a convenience,
x := false
if x := true; x {
fmt.Println(x)
}
fmt.Println(x)
The output in both cases is
true
false
Related
This is function takes two strings and returns struct or nil and I wrote a struct inside this function for use only this function.
type OrgFundingsDetailsFCT struct {
ID int `db:"id"`
OrgProfileID int `db:"org_profile_id"`
OrgID int `db:"org_id"`
RefID string `db:"ref_id"`
AmountUSD float64 `db:"amount_usd"`
FundingDate string `db:"funding_date"`
Status string `db:"status"`
Round string `db:"round"`
CreatedBy string `db:"created_by"`
}
func (s *Server) getCompareOrgFundingsByRefID(refID, status string) (*OrgFundingsDetailsFCT, error) {
type orgFunding struct {
RefID string `db:"ref_id"`
Status string `db:"status"`
}
var orgFundingsDetailsFCT OrgFundingsDetailsFCT
orgfunding := orgFunding{
RefID: refID,
Status: status,
}
const query = `SELECT id,
org_profile_id,
org_id,
ref_id,
amount_usd,
funding_date,
status,round,
created_by
FROM org_fundings
WHERE ref_id=:ref_id AND status=:status`
if err := s.db.NamedGet(&orgFundingsDetailsFCT, query, orgfunding); err == sql.ErrNoRows {
s.logger.Infof("empty rows! getCompareOrgFundingsByRefID #111 %+v", err)
return nil, nil
} else if err != nil {
s.logger.Infof("errors found! getCompareOrgFundingsByRefID#111 %+v", err)
return nil, err
}
return &orgFundingsDetailsFCT, nil
}
Now I'm checking if this function return nil like this
if nil != orgFundingsRefIdPending{
// logic
}
But my question is if I check like that is it same or not?
if orgFundingsRefIdPending != nil{
//logic
}
If nil left side and check with my result is right side OR, my result is left side and check with nil is right side, Is it same? Does that mean the same thing happens if I put nil on either side? also if I use struct on use only function is it valid thing?
The getCompareOrgFundingsByRefID() function returns a pointer and an error value. To check if the return value (the pointer) is nil, simply compare it to nil, e.g.:
var refID, status string
// Set input params
orgFundingsRefIdPending, err := getCompareOrgFundingsByRefID(refID, status)
if err != nil {
// Handle error
}
if orgFundingsRefIdPending != nil {
// Use orgFundingsRefIdPending
}
The == and != comparison operators can only be executed (their result can only be determined) if both of their operands are evaluated. Moreover, since these comparison operators are reflexive (meaning a == b is true only and only if b == a), the order does not matter. So a == b and b == a are equivalent.
The order matters if the operator would not be reflexive (e.g. < so a < b is not the same as b < a), or it could matter if not all operands would be needed for its result, such as the logical OR (||), because we know that if any of the operands of || is true, the result is true regardless of the other value. And since Go's || operator uses short-circuit evaluation (if the result is known before evaluating all operands, the rest are not evaluated, going from left-to-right), the order does matter in case of ||. E.g. in f() || g() if f() returns true, the g() function will not be called.
Note: Back to yoru case, if the returned pointer is not nil but you want to check if the pointed struct value is the zero value of its type, you may simply compare it to OrgFundingsDetailsFCT{}:
if orgFundingsRefIdPending != nil {
// Use orgFundingsRefIdPending
// Is it the zero value?
if *orgFundingsRefIdPending == (OrgFundingsDetailsFCT{}) {
// It's the zero value
}
}
For details and more options, see How to check for an empty struct?
I have written a small constant number expression evaluator. I’m running go-fuzz on it, but it can only detect crashes.
I would like to test that expression considered invalid by my program are really invalid, and valid expression are really valid and yield a correct result.
How could I do that in Go ?
I looked into existing packages like this one, but it allows much more operations and types than I currently support. It thus can’t use it for validation.
The values that I handle are int and float64, and the operations are | & ^ ~(inverse) + - * / %. Also I support the same type of number literals as Go.
I did manual checks but this doesn’t bring me very far. I would need to check the result against another expression evaluator.
You can use go/types and co.:
Constant folding computes the exact constant value (constant.Value)
for every expression (ast.Expr) that is a compile-time constant. Use
Info.Types[expr].Value for the results of constant folding.
I'll use Info.Defs instead of Info.Types as that's simpler for this case, IMO at least.
expr := "float64(20)/6.8"
// parse the expression as part of a file so that it can be type checked
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "x.go", "package x\nconst K = "+expr, 0)
if err != nil {
panic(err)
}
// type check the file so that the constant value gets computed
info := types.Info{Defs: map[*ast.Ident]types.Object{}}
conf := types.Config{}
if _, err := conf.Check("x", fset, []*ast.File{f}, &info); err != nil {
panic(err)
}
// get the value (as string)
for id, obj := range info.Defs {
if id.Name == "K" {
v := obj.(*types.Const).Val()
fmt.Println(v.String())
}
}
https://play.golang.org/p/h2e0No2F1CY
In C and similar languages the following shortcuts can be applied to detect an error and stop on first non-zero result
(void)(result = dosomething() ||
result = dosomething() ||
result = dosomething()
)
if (result == 0 && ...
In golang, I can't seem to do that.
For example:
if result = dosomething() ||
result = dosomething(); result < 0 {
fmt.Printf("Error occurred\n");
}
C is able to treat integers as a boolean expression when checking for non-zero.
for example I can write
if (result = dosomething() || ... )
Instead of
if ( (result = dosomething()) == 0 || ... )
But in go, you can't do that.
I thought I could write:
if result = dosomething() == 0 ||
result = dosomething() == 0; result < 0 {
fmt.Printf("Error occurred\n");
}
But I get an error.
syntax error: result = dosomething() || result used as value
There has to be a way of chaining these together. Or in the style of
javascript promises could a dosomething().doSomething.doSomething.error() approach be possible?
Any creative solutions to this problem? I'm really just wanting to avoid
lots of repetitive code where I want to do a whole bunch of things, but if there is an error at any point stop. Because the error handling logic for each is exactly the same.
See Errors are values on The Go Blog. This article, written by Rob Pike, has an interesting and powerful method of handling errors in a group of functions that works very well.
I have used this technique before several times, and it really works.
For reference, the code used for this technique looks like this (copied from the article):
// Helper type
type errWriter struct {
w io.Writer
err error
}
func (ew *errWriter) write(buf []byte) {
if ew.err != nil {
return
}
_, ew.err = ew.w.Write(buf)
}
//Usage:
ew := &errWriter{w: fd}
ew.write(p0[a:b])
ew.write(p1[c:d])
ew.write(p2[e:f])
// and so on
if ew.err != nil {
return ew.err
}
You could use a slice and a for loop.
https://play.golang.org/p/NJaCliBydA
s := []func() error{do1,do2,do3,do4}
for i := range s {
if err := s[i](); err != nil {
return err
}
}
return nil
Really though, you probably SHOULD follow the examples in the other answer as they come directly from documentation.
This question already has answers here:
What is the idiomatic Go equivalent of C's ternary operator?
(14 answers)
Closed 1 year ago.
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. :/
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.
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 often use the following:
c := b
if a > b {
c = a
}
basically the same as #Not_a_Golfer's but using type inference.
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
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}
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)
}
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)
}
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
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.
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.
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)
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
In go there are functions which return two values or more values, commonly one is an error. Suppose that I want to store the first return value into an already initialized variable, but I would like to initialize the variable to contain the error inline. Is there a way to do this?
For example, say I had this code
var a int
//This code doesn't compile because err doesn't exist
a, err = SomeFuncWithTwoReturnValues()
//This code doesn't compile either
a, err := SomeFuncWithTwoReturnValues()
I know you could do this, but I was hoping there was a way to do it all inline
var a int
var err error
a, err = SomeFuncWithTwoReturnValues()
or
a, err := SomeFuncWithTwoReturnValues()
EDIT: The code above actually compiles, so I looked back at my code to drill down more and have created a quick sample that actually replicates the problem (not just in my mind...).
package main
func myfunc() (int, int) {
return 1, 1
}
func main() {
a := make([]int, 1)
a[0], b := myfunc()
a[0] = b
}
Compiler says main.go|9| non-name a[0] on left side of :=. If I make it = instead of := though then b is never created. I get the feeling that there is not shorthand way to do it though.
As you've mentioned in the comments, you'll need to use the = operator in order to assign to a variable you've already declared. The := operator is used to simultaneously declare and assign a variable. The two are the same:
var x int
x = 5
//is the same as
x := 5
This solution will at least compile:
package main
func myfunc() (int, int) {
return 1, 1
}
func main() {
var b int
a := make([]int, 1)
a[0], b = myfunc()
a[0] = b
}
To answer your question, I don't think there is a way to simultaneously use an undeclared and a declared variable when returning multiple values. That would be trying to use two different operators simultaneously.
Edit: just saw your example from the code that compiles, so it appears you're already familiar with go's assignment operators. I'll leave the example up anyway.
Golang is not a very consistent language. This is a good example. At the beginning I was confused and it would be much simpler if they would always allow the := operator. The compiler is smart enough to detect already declared variables:
package main
import "fmt"
func testFunc() (int,error) {
return 42,fmt.Errorf("Test Error")
}
func main() {
number1,err := testFunc() // OK
number2,err := testFunc() // OK, even if err is already defined
number1,err = testFunc() // OK
// number1,err := testFunc() // ERROR: no new variables on left side of :=
fmt.Println(number1,number2,err)
}
Playground Link: https://play.golang.org/p/eZVB-kG6RtX
It's not consistent, because golang allows you to use := for already declared variables if you assign to them while also introducing a new variable. So the compiler can detect that variables already exists and skip their declaration. But the golang developers decided to allow that only if you introduce at least one new value. The last example shows that.
I ran into this situation like this:
package main
import "os"
func main() {
var cache struct { dir string }
// undefined: err
cache.dir, err = os.UserCacheDir()
// non-name cache.dir on left side of :=
cache.dir, err := os.UserCacheDir()
if err != nil {
panic(err)
}
println(cache.dir)
}
as you discovered, this issue does not have a clean solution. You can declare
an extra variable:
dir, err := os.UserCacheDir()
if err != nil {
panic(err)
}
cache := userCache{dir}
Or, while more verbose, you can declare the error beforehand. This can save
memory, as Go does not use a Rust ownership model:
var (
cache struct { dir string }
err error
)
cache.dir, err = os.UserCacheDir()
As mention in the spec, while using:=, if one of the variables is new, then the old one will just be assigned with the new data.
Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared earlier in the same block (or the parameter lists if the block is the function body) with the same type, and at least one of the non-blank variables is new. As a consequence, redeclaration can only appear in a multi-variable short declaration. Redeclaration does not introduce a new variable; it just assigns a new value to the original.
field1, offset := nextField(str, 0)
field2, offset := nextField(str, offset) // redeclares offset
As mentioned by the other answers you cannot use assignment and declaration in the same return statement. You have to use either.
However I guess the main reason for your question is cleaning up the code so you don't have to declare an extra err variable above the method or function statement.
You can solve this in two ways:
Declare a global var err error variable and use it in the assignment:
var err error
func MyFunc(someInput string) {
var a int
a, err = someOtherFunction()
}
If your method or function returns an error you can use the declared return variable
func MyFunc(someInput string) (err error) {
var a int
a, err = someOtherFunction()
return
}
I mainly have the problem in methods when I want to assign something to a struct member, e.g.:
type MyStruct struct {
so string
}
func (m *MyStruct) SomeMethod() (err error) {
m.so, err = SomeFunction()
// handle error and continue or return it
return
}