Consider the following example illustrating the question (it was just built to explain the question, but I saw similar code in books as well in real projects):
package main
import (
"strconv"
"fmt"
"log"
)
func main() {
n1, err := strconv.Atoi("1")
if err != nil {
log.Panicf("%v", err)
}
n2, err := strconv.Atoi("2")
if err != nil {
log.Panicf("%v", err)
}
// err := fmt.Errorf("new error") <- line 1
// n1, err := strconv.Atoi("3") <- line 2
fmt.Printf("n1 = %d, n2 = %d\n", n1, n2)
}
The compiler doesn't complain about redefining err
, but if I uncomment <- line 1
or <- line 2
, it will complain no new variable on left side of :=
.
So, how does it work? Why the compiler happily allows to override err
in multi return statement, using :=
, but not n1
on <- line 2
example?
Better if you can point into the official reference explaining this behavior.
It is because you used Short variable declaration
:=
. Quoting from the spec:This line:
Is a multi-variable short declaration, and all variables on the left side are new, and so all will be declared (and return values of
strconv.Atoi()
assigned).This line:
It is a multi-variable short declaration, and
n2
is new. So it declaresn2
and only assigns a new value toerr
, becauseerr
is already declared in the same block.This line:
It is not a multi-variable short declaration. It would try to declare
err
but it is already declared in the same block, therefore it is a compile-time error.And this line:
It is a multi-variable short declaration, but all the variables on the left side have been previously declared in the same block, so it is also a compile-time error (it doesn't introduce any new variables on the left side).
Note that if all the variables on the left side have been previously declared, simply changing from Short variable declaration
:=
to Assignment=
will make it work (assumed values on the right side are assignable to the variables on the left side).