此代码编译:
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
身体?
答案 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
可以帮助您找到此类错误。