Short format var declaration in for loop - go

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)
}

Related

Will shorthand declaration of variable, involving already defined one, allocate new memory?

I have a function that returns to values user and err . When I call it in scope I already have variable user, but don’t have variable err , so compiler/linter tells me to use := operator syntax (I know I can declare err somewhere before this call with var declaration), making it look like this:
user := User{"Name"}
...
user, err := functionThatReturnsTwoValues()
if err != nil {
...
Question: In this specific case, in the line user, err := functionThatReturnsTwoValues , will user variable be redeclared?
P.S. I also understand that from actual results, it doesn't matter for me, as in the end, I will have variable with correct data after function call in any case. Also the fact, that variable will be defined in the stack in our case, means there will be no garbage collection involved to clean it up, even if there were 2 User structs initialized.
I think user variable is not re-declared, but of course its value is overridden. I've tested via checking the variable's pointer addresses as below. As you may see the pointers which are used for capturing variable addresses stays same.
https://play.golang.org/p/bj3QwSgCCiG
Snipped:
func main() {
user := User{"Name"}
up1 := &user
user, err := functionThatReturnsTwoValues()
up2 := &user
if err == nil {
fmt.Printf("User: %v \n", user)
fmt.Printf("Pointer check : up1 ?= up2 --> %t [up1=%p, up2=%p]\n", up1 == up2, up1, up2)
fmt.Printf("Value check : *up1 ?= *up2 --> %t \n", *up1 == *up2)
}
}
The output is:
User: {Name2}
Pointer check : up1 ?= up2 --> true [up1=0x40c138, up2=0x40c138]
Value check : *up1 ?= *up2 --> true
The user variable will be used to store the result of the function, see below an example
https://play.golang.org/p/eHHycX4p16j
Yes, the variable is redeclared and its value is overridden. But it must still have the same type declaration. The redeclaration essentially drops down to an assignment and the same stack memory is used.
This is explicitly allowed by the spec to make cases such as defining err neater:
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.
- https://golang.org/ref/spec#Short_variable_declarations
For example:
var user User
user, err := fetchUser() // OK: user redeclared but new err variable declared
user, err := fetchUser() // Bad: user and err variable redeclared, but no new variables declared
user, err = fetchUser() // OK: No declarations, only assignments
In short, yes, the variable user will be redeclared. 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. 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.
See the specification of short variable declaration for more details.
Yes, shorthand declaration will redefine it.
package main
import "fmt"
func main() {
i := 1
i, x := giveMeTwos()
fmt.Println(i, x)
}
func giveMeTwos() (int, int) {
return 2, 2
}

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

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.

Redeclared variable unused

This code compiles:
func (wc *WordCounter) Write(buf []byte) (int, error) {
for adv, i := 0, 0; i < len(buf); i += adv {
adv, _, _ = bufio.ScanWords(buf[i:], true)
*wc++
}
return len(buf), nil
}
But the following does not compile. Notice the short declaration adv, token, _ := .. where I expected that adv would be redeclared (as opposed to be declared as a new var):
func (wc *WordCounter) Write(buf []byte) (int, error) {
for adv, i := 0, 0; i < len(buf); i += adv {
// error: adv declared and not used
adv, token, _ := bufio.ScanWords(buf[i:], true)
fmt.Println(string(token))
*wc++
}
return len(buf), nil
}
According to the Go spec:
a short variable declaration may redeclare variables provided they
were originally declared earlier in the same block. [...] Redeclaration does not introduce a new variable; it just assigns a new value to the original.
I guess this means that the for statement is a block in and of itself, and that adv therefore is considered to be declared over again (as opposed to being redeclared) in the for body?
This is working as intended. Consider the following:
https://play.golang.org/p/cyJZgM5QYn
package main
import (
"fmt"
)
func main() {
for i := 0; i < 10; i++ {
fmt.Printf("%p", &i)
i := i
fmt.Printf(" | %p\n", &i)
}
}
Variables you declare within the for loop header are defined for the entire for loop. The first i printed in the above has the same address on every single iteration. On the other hand, variables declared inside the loop itself are local only to that iteration of the loop! Note that the second i printed on each line has a unique address, as a new variable is being created on each iteration. This makes the lifetime of the two variables, and thus their scopes, different. Since they exist in separate scopes, the inner scope can (usually inadvertently) shadow the outer scope variable via the short-form declaration.
I guess this means that the for statement is a block in and of itself,
and that adv therefore is considered to be declared over again (as
opposed to being redeclared) in the for body?
Yes, that's correct. Go specs say following about blocks:
A block is a possibly empty sequence of declarations and statements
within matching brace brackets.
Each "if", "for", and "switch" statement is considered to be in its own implicit block.
So you are declaring a new variable in your for-block with the same name as the previously declared variable. The new variable shadows the previously declared variable making it inaccessible from inside the for-block.
This is a common source of bugs if you don't realize there are now two variables with the same name and you think you are assigning values to the variable you declared in the outer block. go vet with the -shadow=true option can help find such bugs.

What is the difference between := and = in Go?

I am new to Go programming language.
I noticed something strange in Go: I thought that it used := and substitutes = in Python, but when I use = in Go it is also works.
What is the difference between := and =?
= is assignment. more about assignment in Go: Assignments
The subtle difference between = and := is when = used in variable declarations.
General form of variable declaration in Go is:
var name type = expression
the above declaration creates a variable of a particular type, attaches a name to it, and sets its initial value. Either the type or the = expression can be omitted, but not both.
For example:
var x int = 1
var a int
var b, c, d = 3.14, "stackoverflow", true
:= is called short variable declaration which takes form
name := expression
and the type of name is determined by the type of expression
Note that: := is a declaration, whereas = is an assignment
So, a short variable declaration must declare at least one new variable. which means a short variable declaration doesn't necessarily declare all the variables on its left-hand side, when some of them were already declared in the same lexical block, then := acts like an assignment to those variables
For example:
r := foo() // ok, declare a new variable r
r, m := bar() // ok, declare a new variable m and assign r a new value
r, m := bar2() //compile error: no new variables
Besides, := 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.
More info:
variable declarations
short variable declarations
= is just assignment
:= is declare-and-initialize construct for new vars (at least one new var) inside the function block (not global):
var u1 uint32 //declare a variable and init with 0
u1 = 32 //assign its value
var u2 uint32 = 32 //declare a variable and assign its value at once
//declare a new variable with defining data type:
u3 := uint32(32) //inside the function block this is equal to: var u3 uint32 = 32
fmt.Println(u1, u2, u3) //32 32 32
//u3 := 20//err: no new variables on left side of :=
u3 = 20
fmt.Println(u1, u2, u3) //32 32 20
u3, str4 := 100, "str" // at least one new var
fmt.Println(u1, u2, u3, str4) //32 32 100 str
:= is the "short declaration form" for declaring and initializing variables. It does type inference on the value that you are assigning to set the variable's type.
If you attempt to assign with the short declaration form to the same variable in the same scope, the compiler will throw an error.
Be on the lookout for the short declaration form "shadowing" the same variable in an enclosing scope (especially with errors)
= requires the var keyword when declaring a variable and the variable's type explicitly following the variable name. You can actually leave the = off the declaration since Go has a initial value for all types (strings are initialized as "", ints are 0, slices are empty slices). It can also be used for reassignment with just a value, ie
var s string = "a string" // declared and initialized to "a string"
s = "something else" // value is reassigned
var n int // declared and initialized to 0
n = 3
Inside a function, the := short assignment statement can be used in place of a var declaration with implicit type.
for example:
package main
import "fmt"
func main() {
var i, j int = 1, 2
k := 3
c, python, java := true, false, "no!"
fmt.Println(i, j, k, c, python, java)
}
NOTICE: the variable declared with := can only be used inside the function block.
I took time to figure out a mistake I made that could help you to clarify the difference between := and =.
Consider the following code:
type mystruct struct {
a int
arr []int
}
func main() {
m := mystruct{}
m.arr := make([]int, 5) //compilation error because m.arr is already declared.
m.arr = make([]int, 5) //compiles
}
= is used as statically typed.
:= is used as dynamically typed.
example:
var a = 30 # statically typed and is a compile time check
b := 40 # dynamically checked.
Note the difference in := and = in range clauses as well. The following examples are adapted from the spec.
The iteration variables may be declared by the "range" clause using a form of short variable declaration (:=). In this case their types are set to the types of the respective iteration values and their scope is the block of the "for" statement; they are re-used in each iteration. If the iteration variables are declared outside the "for" statement, after execution their values will be those of the last iteration.
= range ...:
i := 2
x = []int{3, 5, 7}
for i, x[i] = range x { // i,x[2] = 0,x[0]
break
}
// now i == 0 and x == []int{3, 5, 3}
var (key string; val interface{})
m := map[string]int{"mon":0, "tue":1, "wed":2, "thu":3, "fri":4, "sat":5, "sun":6}
for key, val = range m {
h(key, val)
}
// key == last map key encountered in iteration (note order of map iteration is random)
// val == map[key]
:= range ...:
var a [10]string
for i, s := range a {
// type of i is int, type of s is string
// s == a[i]
someFunction(i, s)
}
// i and s are no longer accessible here.
for i := range a { // roughly equivalent to `for i := 0; i < len(a); i++`
someFunction(i, a[i])
}
for _, s := range a {
anotherFunc(s)
}
// Above is roughly equivalent to:
{
var s string
for i := 0; i < len(a); i++ {
s = a[i]
anotherFunc(s)
}
}
// s not accessible here
The most verbose way to declare a variable in Go uses the var keyword, an explicit type, and an assignment.
var x int = 10
Go also supports a short declaration format. When you are within a function, you can
use the := operator to replace a var declaration that uses type inference.
var x = 10
x := 10
There is one limitation on :=. If you are declaring a variable at package level, you
must use var because := is not legal outside of functions.
There are some situations within functions where you should avoid :=
When initializing a variable to its zero value, use var x int. This makes it clear
that the zero value is intended.
When assigning an untyped constant or a literal to a variable and the default type
for the constant or literal isn’t the type you want for the variable, use the long var
form with the type specified. While it is legal to use a type conversion to specify
the type of the value and use := to write x := byte(20), it is idiomatic to write
var x byte = 20.
Because := allows you to assign to both new and existing variables, it sometimes
creates new variables when you think you are reusing existing ones. In those situations, explicitly declare all
of your new variables with var to make it clear which variables are new, and then
use the assignment operator (=) to assign values to both new and old variables.
While var and := allow you to declare multiple variables on the same line, only use
this style when assigning multiple values returned from a function or the comma ok
idiom.
Learning Go Jon Bondner

Go: transfer var into anonymous function

I am having trouble transferring a variable into an anonymous function. Is there a solution?
import "github.com/lxn/walk"
***
var openAction [12]*walk.Action
for i := 0; i < 12; i++ {
openBmp, err := walk.NewBitmapFromFile(_films[i][0])
if err != nil {
log.Printf("Open bitmap for buildBody() :%v\n", err)
}
openAction[i] = walk.NewAction()
openAction[i].SetImage(openBmp)
openAction[i].SetText(_films[i][2])
openAction[i].Triggered().Attach( func(){
exec(i)
})
mw.ToolBar().Actions().Add(openAction[i])
}
exec(i) where i always = 11
for i := 0; i < 12; i++ {
i := i
...
Crazy as it looks, this is something you will see in Go code. It results from the way closures work and the way variables are scoped. Your anonymous function is a closure that captures i. Specifically, it is capturing a variable called i, not the current value of i, and it captures whatever i is in scope. In your original code this is the loop variable, which is the same variable for each iteration of the loop. All of your closures captured the same variable. The addition of i := i declares a new variable on each iteration. Now each closure will capture this new variable, and on each iteration it will be a different variable.
In a little more detail, the scope of the loop variable i is the for statement. This includes the loop block, but since the declaration of the loop variable i is outside of the block, declaring a new variable with the same name inside the block is legal and creates a new variable at that point in the block. The loop variable is then shadowed. Often a variable declared like this goes on the stack, but in this case compiler escape analysis sees that your closure is still referring to this block variable when it goes out of scope at the end of the block, and so the variable is placed on the heap. On each iteration, the block is reentered and a new variable i is placed on the heap.
I think that this will get you what you want:
openAction[i].Triggered().Attach(func(x int) func() {
return func() { exec(x) }
}(i))
The trick is to have your anonymous function return an anonymous function, and each created function will enclose each of the values of i.
You are encountering a quirk of go's for loops. The i variable in the loop is not a new variable for each iteration. because of this all of your closures are closing over the same variable whose value is changing underneath them. When your code runs after the loop all of the functions see the value 11 for the i they closed over.
The solution is to pass the i into a function which then returns another function that closes over the functions arg. This is why Adam Crosslands solution works.

Resources