Reputation: 2415
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?
Upvotes: 0
Views: 389
Reputation: 3274
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.
Upvotes: 1
Reputation: 10158
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.
Upvotes: 4