Reputation: 458
For the following code, It seems going into dead loop.
After s, err := minusOne(s)
, s is shorten according the log info.
But the before minus log shows that it never changed.
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
}
}
}
If I change it slightly like, it works like expected.
s1, err := minusOne(s)
s = s1
Or if I remove the err returning in the minusOne function, and it also works.
s = minusOne(s)
I really can't understand it. Anyone can help with it?
Upvotes: 1
Views: 65
Reputation: 10264
On each iteration you declare new variables called s
and err
:
s, err := minusOne(s)
Their scope is only the current iteration, so the above line keeps using the same s
variable declared outside of the loop. From Declarations and scope part of The Go Specification:
Go is lexically scoped using blocks:
- The scope of a constant or variable identifier declared inside a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl for short variable declarations) and ends at the end of the innermost containing block.
To fix it, you need to use assignment:
var err error
for {
// ...
s, err = minusOne(s)
// ...
}
Upvotes: 5
Reputation: 2371
You are using the short var declaration :=
. You must take care with this.
Inside the for
loop you are creating two new variables, err
, but also s
(with a new scope inside the for loop). This wouldn't be a problem if you do in the same scope.
You can simply extract the err
to a pre-declared variable before like that:
var err error
s, err = minusOne(s)
Upvotes: 3
Reputation: 86
do not use s in the for loop, := will add a new local var. just rename the s in for loot to s1. You can also declare a outside for loop and replace := with =
Upvotes: 1