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.
Related
This code:
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello, playground")
var a bool
var b interface{}
b = true
if a, ok := b.(bool); !ok {
fmt.Println("Problem!")
}
}
Yields this error in the golang playground:
tmp/sandbox791966413/main.go:11:10: a declared and not used
tmp/sandbox791966413/main.go:14:21: a declared and not used
This is confusing because of what we read in the short variable declaration golang docs:
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, my questions:
Why can't I redeclare the variable in the code snippet above?
Supposing I really can't, what I'd really like to do is find
a way to populate variables with the output of functions while
checking the error in a more concise way. So is there any way
to improve on the following form for getting a value out of an
error-able function?
var A RealType
if newA, err := SomeFunc(); err != nil {
return err
} else {
A = newA
}
This is happening because you are using the short variable declaration in an if initialization statement, which introduces a new scope.
Rather than this, where a is a new variable that shadows the existing one:
if a, ok := b.(bool); !ok {
fmt.Println("Problem!")
}
you could do this, where a is redeclared:
a, ok := b.(bool)
if !ok {
fmt.Println("Problem!")
}
This works because ok is a new variable, so you can redeclare a and the passage you quoted is in effect.
Similarly, your second code snippet could be written as:
A, err := SomeFunc()
if err != nil {
return err
}
You did redeclare the variable, that is the problem. When you redeclare a variable, it is a different variable. This is known as "shadowing".
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello, playground")
// original a.
var a bool
var b interface{}
b = true
// redeclared a here. This is a a'
if a, ok := b.(bool); !ok {
// a' will last until the end of this block
fmt.Println("Problem!")
}
// a' is gone. So using a here would get the original a.
}
As for your second question. That code looks great. I would probably switch it to if err == nil (and swap the if and else blocks). But that is a style thing.
The error raised by the compiler is saying that both declarations of variable a are not being used.
You're actually declaring a twice, when using short declaration in the if condition you're creating a new scope that shadows the previous declaration of the variable.
The actual problem you're facing is that you're never using the variable value which, in Go, is considered a compile time error.
Regarding your second question, I think that the shortest way to get the value and check the error is to do something similar to this:
func main() {
a, ok := someFunction()
if !ok {
fmt.Println("Problem!")
}
}
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)
}
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
}
This code:
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello, playground")
var a bool
var b interface{}
b = true
if a, ok := b.(bool); !ok {
fmt.Println("Problem!")
}
}
Yields this error in the golang playground:
tmp/sandbox791966413/main.go:11:10: a declared and not used
tmp/sandbox791966413/main.go:14:21: a declared and not used
This is confusing because of what we read in the short variable declaration golang docs:
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, my questions:
Why can't I redeclare the variable in the code snippet above?
Supposing I really can't, what I'd really like to do is find
a way to populate variables with the output of functions while
checking the error in a more concise way. So is there any way
to improve on the following form for getting a value out of an
error-able function?
var A RealType
if newA, err := SomeFunc(); err != nil {
return err
} else {
A = newA
}
This is happening because you are using the short variable declaration in an if initialization statement, which introduces a new scope.
Rather than this, where a is a new variable that shadows the existing one:
if a, ok := b.(bool); !ok {
fmt.Println("Problem!")
}
you could do this, where a is redeclared:
a, ok := b.(bool)
if !ok {
fmt.Println("Problem!")
}
This works because ok is a new variable, so you can redeclare a and the passage you quoted is in effect.
Similarly, your second code snippet could be written as:
A, err := SomeFunc()
if err != nil {
return err
}
You did redeclare the variable, that is the problem. When you redeclare a variable, it is a different variable. This is known as "shadowing".
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello, playground")
// original a.
var a bool
var b interface{}
b = true
// redeclared a here. This is a a'
if a, ok := b.(bool); !ok {
// a' will last until the end of this block
fmt.Println("Problem!")
}
// a' is gone. So using a here would get the original a.
}
As for your second question. That code looks great. I would probably switch it to if err == nil (and swap the if and else blocks). But that is a style thing.
The error raised by the compiler is saying that both declarations of variable a are not being used.
You're actually declaring a twice, when using short declaration in the if condition you're creating a new scope that shadows the previous declaration of the variable.
The actual problem you're facing is that you're never using the variable value which, in Go, is considered a compile time error.
Regarding your second question, I think that the shortest way to get the value and check the error is to do something similar to this:
func main() {
a, ok := someFunction()
if !ok {
fmt.Println("Problem!")
}
}
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.