Short assignment statement looking weird

As part of learning Golang, I have reached the short assignment statement but it’s really confusing when it’s using twice or more in the source file.

//more code
err := value
....
...
err : value
// more code

After running this kind of I’m getting this kind of error -> /prog.go:10:4: no new variables on left side of :=

Apart from this, I have coded some generic code Golang but it’s doesn’t throw any kind of error for the same one mentioned above.

code link: https://play.golang.org/p/JKa0Q7vVwC4

package main

import (
	"fmt"
	"log"
)

func main() {

	value1, err := "VALUE1", "ERROR"

	if err != "ERROR" {
		log.Fatal(err)
	}

	fmt.Println(value1)

	value2, err := "VALUE2", "Error"

	if err != "Error" {
		log.Fatal(err)
	}

	fmt.Println(value2)
}

output

VALUE1
VALUE2

Program exited.

In this code err variable used 2 times with := short assignment statement. It’s really running with any exception.

Hi, Community please explain to me how this is happening.

1 Like

The reasons your 2nd short assignment gets through is because value2 is indeed new to “delcare and define”. Go allows multiple short assignments only there is new variable.

HOWEVER, the above is not applicable for assignment in reference (e.g. struct field). In that case, you need to declare the err variable first then assign accordingly. Example, this won’t work:

s := &MyStruct{A: 0}   // some kind of struct

s.A, err := somefunc(...)   // err is new variable

This works:

var err error
s := &MyStruct{A: 0}   // some kind of struct

s.A, err = somefunc(...)  

Explanation

Short assignment is merely a “shortcut” to declare and define, example:

var err error                      // declare err
err = someFunc(...)                // define err
err = anotherFunc(...)             // define err

into a single line:

err := someFunc(...)               // declare and define err
err = anotherFunc(...)             // define err

The general rule of thumb is every variable can only declare once, and define many times after declaration. Therefore, the following won’t work:

err := someFunc(...) # declare and define
err := anotherFunc(...) # ERROR: re-declared and define
1 Like

Hello @hollowaykeanho, Thank you for your valuable update, but still confusion going on.

value1, err := "VALUE1", "ERROR"
....
value2, err := "VALUE2", "ERROR"

Both this kind in the source doesn’t cause an exception. It defines and declares the same variable 2 times.

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

and more

https://play.golang.org/p/xDD57i4Ohrs
both variables have the same address too.

1 Like

It never need to because:

  1. It’s not assignment to referenced variable.
  2. value2 is indeed requiring declaration. If I break it down:
value1, err := "v1", "e1"           # value 1 = [Declare and Define], err = [Declare and Define]
...
value2, err := "v2", "e2"           # value 2 = [Declare and Define], err = [Define]
...
value3, err := "v3", "e3"           # value 3 = [Declare and Define], err = [Define]
...
value2, err = "v4", "e4"           #  value 2 = [Define], err = [Define]
...
value2, err := "v5", "e5"           # ERROR: value 2 = [RE-Declare and Define], err = [RE-Declare and Define]

Go accepts this short assignment when it comes to multiple variables. Your second example is aligned to my explanation (err should be the same object).

2 Likes

Read the The Go Programming Language Specification.

Especially Short variable declarations.

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.

Run this program:

package main

import (
    "fmt"
    "log"
)

func main() {
    value1, err := "VALUE1", "ERROR"
    fmt.Printf("%p %p\n", &value1, &err)
    if err != "ERROR" {
	    log.Fatal(err)
    }
    fmt.Println(value1, err)

    value2, err := "VALUE2", "Error"
    fmt.Printf("%p %p\n", &value2, &err)
    if err != "Error" {
	    log.Fatal(err)
    }
    fmt.Println(value2, err)
}
0xc0000961e0 0xc0000961f0
VALUE1 ERROR
0xc000096220 0xc0000961f0
VALUE2 Error

The output is as expected.

2 Likes

Thank you @hollowaykeanho :heart:

1 Like

Thank you @petrus :heart:

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.