重新声明的变量未使用

时间:2017-10-26 15:01:00

标签: go

此代码编译:

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
}

但以下内容无法编译。请注意简短声明adv, token, _ := ..,我希望adv重新声明(而不是声明为新的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
}

根据Go规范:

  

短变量声明可以重新声明提供的变量   最初在同一个区块中被宣布。 [...] Redeclaration 不会引入新变量;它只是为原始版本赋予了一个新值。

我想这意味着for语句本身就是一个块,因此adv被认为是重新声明(而不是重新声明)在for身体?

2 个答案:

答案 0 :(得分:4)

这是按预期工作的。请考虑以下事项:

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

for循环标头中声明的变量是为整个for循环定义的。上面打印的第一个i在每次迭代中都具有相同的地址。另一方面,在循环内部声明的变量本身只是局部循环的迭代!请注意,每行打印的第二个i都有一个唯一的地址,作为一个新的变量正在每次迭代中创建。这使得两个变量的寿命以及它们的范围不同。由于它们存在于不同的范围内,因此内部范围可以(通常是无意中)通过短格式声明来影响外部范围变量。

答案 1 :(得分:1)

  

我想这意味着for语句本身就是一个块,   因此,这被认为是重新宣布的(如   反对被重新宣布的身体?

是的,这是正确的。 Go规格说关于块:

  

块是一个可能为空的声明和语句序列   在匹配的括号内。

     

每个“if”,“for”和“switch”语句都被认为是在它自己的隐式块中。

因此,您在for-block中声明了一个与先前声明的变量同名的新变量。新变量会影响先前声明的变量,使其无法从for-block内部访问。

如果您没有意识到现在有两个具有相同名称的变量,并且您认为要为在外部块中声明的变量赋值,则这是常见的错误源。使用go vet选项的-shadow=true可以帮助您找到此类错误。