augustzf
augustzf

Reputation: 2415

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?

Upvotes: 0

Views: 389

Answers (2)

jussius
jussius

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

Kaedys
Kaedys

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

Related Questions