奇怪的行为,同时变量作为函数的输入和输出

时间:2018-04-28 11:23:25

标签: string go variable-assignment

对于以下代码,它似乎进入死循环。 在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)

我真的无法理解它。 任何人都可以帮忙吗?

3 个答案:

答案 0 :(得分:5)

在每次迭代中,您声明名为serr的新变量:

s, err := minusOne(s)

它们的作用域只是当前的迭代,因此上面的行继续使用在循环外声明的相同s变量。来自The Go Specification的Declarations and scope部分:

  

Go使用块进行词法作用:

     
      
  1. 在函数内声明的常量或变量标识符的范围从ConstSpec或VarSpec(短变量声明的ShortVarDecl)的末尾开始,并在最内层包含块的末尾结束。
  2.   

要修复它,您需要使用赋值:

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 =