Why does initializing just one variable in a definition fail, in golang - go

In calling a library function with the following signature:
func New() (*sql.DB, Sqlmock, error)
like this:
suite.db, suite.mock, err := sqlmock.New() // inside a suite method
I get error
expected identifier on left side of :=
However, when I change to this
var err error
suite.db, suite.mock, err = sqlmock.New()
the error disappears! Why does declaring k < n variables in a := assignment fail?!

:= is not assignment, it is a short variable declaration. Assignment uses e.g. the simple = operator.
As its name says: it is to declare variables. suite.db is not a variable, it is an expression, more specifically a primary expression; a selector to be exact.
The short variable declaration uses the syntax:
ShortVarDecl = IdentifierList ":=" ExpressionList .
Where IdentifierList is:
IdentifierList = identifier { "," identifier } .
So you must list identifiers. One "exception" to this "declare new variables rule" is the redeclaration:
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.
So you are allowed to use existing variables in a short variable declaration if they were declared in the same block, and you also provide new identifiers (not just existing ones–in which case you would have to use assignment instead).
See related: Why there are two ways of declaring variables in Go, what's the difference and which to use?
When you declare err prior and change := to = it works, because the assignment does not require identifiers on the left of the assignment operator, but expressions:
Assignment = ExpressionList assign_op ExpressionList .
And as detailed above, suite.db is an expression, just like existing variables (identifiers).

:= declares a new variable "identifier". This means you are adding a named thing in your program that can be assigned a value. A struct's fields already are named, as in the golang parser knows they exist so using := makes no sense to golang in this case.
Why does declaring k < n variables in a := assignment fail?!
I'm not sure what "k < n" means, but I think you mean "why does having multiple variables on the left side of := fail?". If that's what you mean, that's not true.
x, y, z := func() (int,int,int) {return 1,2,3}()
fmt.Println(x, y, z)
works just fine. The issue is that golang cannot create an "identifier" (aka a newly named variable) for a struct field since that struct field already exists.
EDIT:
I just had a brainwave that you might have mean "why does having only some new identifiers to declare on the left side of := not work?". This also is not true.
x, y := 5, 6
fmt.Println(x, y)
x, y, z := 1, 2, 3
fmt.Println(x, y, z)
The above works just fine as well.

Related

Short format var declaration in for loop

Please see the code below. (A) is not ok in Go and I understand why. But why is (B) ok in Go ?
(A) is not ok: because re-definition of a (no new var in LHS of := )
(B) should be an error too: because re-definition of r (no new var in LHS of := ) as the loop will execute r := with each iteration while r is still in scope.
package main
import "fmt"
func main() {
a := make([]byte, 10)
fmt.Println(a)
a := make([]byte, 10) //not ok and I understand why : (A)
fmt.Println(a)
for i := 0; i < 5; i++ {
r := make([]byte, 10) //ok, but why is this ok? : (B)
fmt.Println(r)
}
}
The key idea behind the short format declaration is that it has to define at least one new variable in the current block. So it fails in the first case because it is attempting to redefine a in the current block without introducing any new variables. The second block works, because r is a new variable declared in the current block.
As describe in go doc specifications about Short_variable_declarations, it is temporary for the scope.
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.
Short variable declarations may appear only inside functions. In some contexts such as the initializers for "if", "for", or "switch" statements, they can be used to declare local temporary variables.
You can not redeclare same variable with short variable declaration in same scope.
a, a := 1, 2 // illegal: double declaration of a or no new variable if a was declared elsewhere
In your case, r is in loop scope and each iteration r is a new variable. Because for loop repeats execution of a block.
A "for" statement specifies repeated execution of a block
If you need to clarify this please run below loop code and see r's memory addresses for each iterations. It will print five different addresses.
for i := 0; i < 5; i++ {
r := make([]byte, 10) //ok, but why is this ok? : (B)
fmt.Printf("%p\n",r)
}

Understanding variable scope in Go

I am going through the Go specification to learn the language, and these points are taken from the spec under Declarations and scope.
Though I am able to understand points 1-4, I am confused on points 5 and 6:
The scope of a constant or variable identifier declared inside a
function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
for short variable declarations) and ends at the end of the
innermost containing block.
The scope of a type identifier declared inside a function begins at
the identifier in the TypeSpec and ends at the end of the innermost
containing block.
This is the code which I used to understand scope in Go:
package main
import "fmt"
func main() {
x := 42
fmt.Println(x)
{
fmt.Println(x)
y := "The test message"
fmt.Println(y)
}
// fmt.Println(y) // outside scope of y
}
From this what I understand is scope of x is within the main function, and the scope of y is inside the opening and closing brackets after fmt.Println(x), and I cannot use y outside of the closing brackets.
If I understand it correctly, both points 4 and 5 are saying the same thing. So my questions are:
If they are saying the same thing, what is the importance of both the
points?
If they are different, can you please let me know the difference?
They're making the same point, with the same rules, about two different things: the first is about variables and constants, the second is about type identifiers. So, if you declare a type inside a block, the same scoping rules apply as would apply to a variable declared at the same spot.
Besides applying to different things (rule #5 is for constant- and variable declarations, rule #6 is for type declarations), there is also an important difference in wording:
The scope of a constant or variable identifier declared inside a
function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
for short variable declarations) and ends at the end of the
innermost containing block.
The scope of a type identifier declared inside a function begins at
the identifier in the TypeSpec and ends at the end of the innermost
containing block.
This is the reason why there are 2 rules and not one.
What does this mean? What does the difference imply?
# 5 Variable and Constant declarations (inside a function)
The scope of the declared variables or constants begins at the end of the declaration. This means if you're creating a function variable, initializing it with an anonymous function, it can't refer to itself.
This is invalid:
f := func() {
f()
}
Attempting to compile:
prog.go:5:3: undefined: f
This is because the declaration ends after the closing bracket of the anonymous function, so inside of it you can't call f(). A workaround would be:
var f func()
f = func() {
f()
}
Now here the declaration of f ends at the closing parenthesis (of its type func()), so in the next line when we assign an anonymous function to it, it is valid to refer to f (to call the function value stored in the f variable) because it is now in scope. See related question: Define a recursive function within a function in Go
Similarly, when initializing a variable e.g. with a composite literal, you can't refer to the variable inside of it:
var m = map[int]string{
1: "one",
21: "twenty-" + m[1],
}
This gives a compile-time error ("undefined: m"), because m is not in scope yet inside the composite literal.
And obviously this workaround works:
var m = map[int]string{
1: "one",
}
m[21] = "twenty-" + m[1]
# 6 Type declarations (inside a function)
The scope of the declared type begins at the identifier in the declaration. So in contrast to rule #5, it is valid to refer to the type itself inside its declaration.
Does it have any advantage / significance?
Yes, you can declare recursive types, such as this:
type Node struct {
Left, Right *Node
}
The type identifier Node is in scope right after it appears in the type declaration, which ends with the closing bracket, but before that we could refer to it, meaningfully.
Another example would be a slice type whose element type is itself:
type Foo []Foo
You can read more about it here: How can a slice contain itself?
Yet another valid example:
type M map[int]M

Golang: Scope of multi return values from function

When a function returns more than one variable in Golang, what's the scope of the variables? In the code attached, I can't figure out the scope of b.
package main
import (
"fmt"
)
func addMulti(x, y int) (int, int) {
return (x + y), (x * y)
}
func main() {
//what is the scope of the b variable here?
a, b := addMulti(1, 2)
fmt.Printf("%d %d\n", a, b)
//what is the scope of the b variable here?
c, b := addMulti(3, 4)
fmt.Printf("%d %d\n", c, b)
}
We're not talking about the scope of the return value of a function but rather the scope of the variable you assign the return value to.
The scope of the variable b in your case is the function body, from the point at which you declare it.
At first you do it at this line:
a, b := addMulti(1, 2)
But then you use another Short Variable declaration at this line:
c, b := addMulti(3, 4)
which - since b is already declared - just assigns a new value to it. b will be in scope until the end of your main() function. Quoting from the Go Language Specification:
Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared earlier in the same block 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.
It's a normal variable inside a block. From the spec:
The scope of a constant or variable identifier declared inside a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl for short variable declarations) and ends at the end of the innermost containing block.
In the second call, you're just reassigning the value of the same b variable. Its scope is the same.
The scope of b variable is main.main(). In second assignment c, b := addMulti(3, 4) you introduce new variable c, and assign variable b introduced in first assignment. If you change second assignment to be a, b := addMulti(3, 4) same as first it want not to compile.

var vs := in Go

In the Go web server example here: http://golang.org/doc/effective_go.html#web_server
The following line of code works
var addr = flag.String("addr", ":1718", "http service address")
but changing it to
addr := flag.String("addr", ":1718", "http service address")
is a compilation error. Why? Does it have anything to do with the face that the return type of the function is *string instead of string? What difference does that make?
UPDATE: Thanks for pointing out that := is not allowed at the top level. Any idea why this inconsistency is in the spec? I don't see any reason for the behaviour to be different inside a block.
In Go, top-level variable assignments must be prefixed with the var keyword. Omitting the var keyword is only allowed within blocks.
package main
var toplevel = "Hello world" // var keyword is required
func F() {
withinBlock := "Hello world" // var keyword is not required
}
On the updated question: there is actually a difference between long and short declarations, being in that short form allows redeclaration of variables.
From spec:
Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared earlier in the same block 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
a, a := 1, 2 // illegal: double declaration of a or no new variable if a was declared elsewhere
So I'd say the := operator is not pure declare, but more like declare and assign.
Redeclaration in toplevel is not allowed, so neither are short declarations.
Another reason for this might be syntax simplicity. In Go all toplevel forms start with either type, var or func. Short declarations there will ruin all the cuteness.
The Go Programming Language Specification
Short variable declarations
A short variable declaration uses the syntax:
ShortVarDecl = IdentifierList ":=" ExpressionList .
Short variable declarations may appear only inside functions.
In your example, changing the variable declaration statement outside a function body
var addr = flag.String("addr", ":1718", "http service address")
to a short variable declaration statement outside a function body
addr := flag.String("addr", ":1718", "http service address")
fails with compiler error "non-declaration statement outside function body."

What does := mean in Go?

I'm following this tutorial, specifically exercise 8:
http://tour.golang.org/#8
package main
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("hello", "world")
fmt.Println(a, b)
}
Specifically what does the := mean? Searching for Go documentation is very hard, ironically.
A short variable declaration uses the syntax:
ShortVarDecl = IdentifierList ":=" ExpressionList .
It is a shorthand for a regular variable declaration with initializer expressions but no types:
Keep on going to page 12 of the tour!
A Tour of Go
Short variable declarations
Inside a function, the := short assignment statement can be used in
place of a var declaration with implicit type.
(Outside a function, every construct begins with a keyword and the :=
construct is not available.)
As others have explained already, := is for both declaration, and assignment, whereas = is for assignment only.
For example, var abc int = 20 is the same as abc := 20.
It's useful when you don't want to fill up your code with type or struct declarations.
The := syntax is shorthand for declaring and initializing a variable, example f := "car" is the short form of var f string = "car"
The short variable declaration operator(:=) can only be used for declaring local variables. If you try to declare a global variable using the short declaration operator, you will get an error.
Refer official documentation for more details
:= is not an operator. It is a part of the syntax of the Short variable declarations clause.
more on this: https://golang.org/ref/spec#Short_variable_declarations
According to my book on Go, it is just a short variable declaration statement
exactly the same as
var s = ""
But it is more easy to declare, and the scope of it is less expansive. A := var decleration also can't have a type of interface{}. This is something that you will probably run into years later though
:= represents a variable, we can assign a value to a variable using :=.

Resources