对于以下代码,它似乎进入死循环。
在s, err := minusOne(s)
之后,根据日志信息缩短s。
但是之前的减号日志表明它从未改变过。
func minusOne(s string) (string, error) {
if len(s) >= 0 {
return s[1:], nil
}
return "", nil
}
func TestStr(t *testing.T) {
s := "hello world"
for {
log.Println("before minus", s)
s, err := minusOne(s)
log.Println("after minus", s)
if err == nil && len(s) == 0 {
break
}
}
}
如果我稍微改变一下,它会像预期的那样工作。
s1, err := minusOne(s)
s = s1
或者如果我删除了在minusOne函数中返回的错误,它也可以工作。
s = minusOne(s)
我真的无法理解它。 任何人都可以帮忙吗?
答案 0 :(得分:5)
在每次迭代中,您声明名为s
和err
的新变量:
s, err := minusOne(s)
它们的作用域只是当前的迭代,因此上面的行继续使用在循环外声明的相同s
变量。来自The Go Specification的Declarations and scope部分:
Go使用块进行词法作用:
- 在函数内声明的常量或变量标识符的范围从ConstSpec或VarSpec(短变量声明的ShortVarDecl)的末尾开始,并在最内层包含块的末尾结束。
醇>
要修复它,您需要使用赋值:
var err error
for {
// ...
s, err = minusOne(s)
// ...
}
答案 1 :(得分:3)
您正在使用短变量声明:=
。你必须小心这一点。
在for
循环中,您创建了两个新变量err
,还有s
(在for循环中有一个新范围)。如果你在相同的范围内,这不会是一个问题。
您可以像这样简单地将err
提取到预先声明的变量:
var err error
s, err = minusOne(s)
答案 2 :(得分:1)
不要在for循环中使用s,:=将添加一个新的局部变量。只需将战利品重命名为s1。您还可以声明一个外部for循环并替换:= with =