spf13 / cast

safe and easy casting from one type to another in Go

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

toInt/toInt64 is wrong

liuaiyuan opened this issue · comments

var value = "00100"
fmt.Println(strconv.ParseInt(value, 10, 64))
fmt.Println(strconv.Atoi(value))
fmt.Println(cast.ToInt64E(value))
fmt.Println(cast.ToIntE(value))

output

100 <nil> ✅
100 <nil> ✅
64 <nil> ❌
64 <nil>
var value = "012345678"
fmt.Println(strconv.ParseInt(value, 10, 64))
fmt.Println(strconv.Atoi(value))
fmt.Println(cast.ToInt64E(value))
fmt.Println(cast.ToIntE(value))

output

12345678 <nil> ✅
12345678 <nil> ✅
0 unable to cast "012345678" of type string to int64 ❌
0 unable to cast "012345678" of type string to int ❌

The "is wrong" statement is a little bombastic -- but the current behaviour is certainly a little undocumented. But it's certainly in line with the corresponding documentation in Go's stdlib.

https://play.golang.org/p/fMXB0rEgN9Z

The "is wrong" statement is a little bombastic -- but the current behaviour is certainly a little undocumented. But it's certainly in line with the corresponding documentation in Go's stdlib.

https://play.golang.org/p/fMXB0rEgN9Z

Okay, thank you very much for your reply, but for special values, this will not apply and the developer needs to deal with it by himself

@liuaiyuan this isn't my library and I did not implement these, and I would probably also prefer that they behaved the way you describe, but that would probably be too much of a breaking change.

/cc @spf13

you could create a pr :)

the problem could be fixed with changing the v, err := strconv.ParseInt(s, 0, 0) 's to v, err := strconv.ParseInt(s, 10, 0) ...

I did this and added to the tests for your scenario, and it works... what makes me hesitate to submit a pr is I do not know what this breaks for people, even though this "fix" is how I would expect it to work there's probably a lot I'm not considering...

I modified all the "to" functions and tests, but this is part of the diff to illustrate my meaning

@ -345,6 +349,10 @@ func TestToInt64E(t *testing.T) {
                {true, 1, false},
                {false, 0, false},
                {"8", 8, false},
+               {"-8", -8, false},
+               {"0100", 100, false},
+               {"01234", 1234, false},
+               {"1234", 1234, false},
                {nil, 0, false},
                // errors
                {"test", 0, true},
diff --git a/caste.go b/caste.go
index 70c7291..6ccc2d0 100644
--- a/caste.go
+++ b/caste.go
@@ -211,7 +211,7 @@ func ToInt64E(i interface{}) (int64, error) {
        case float32:
                return int64(s), nil
        case string:
-               v, err := strconv.ParseInt(s, 0, 0)
+               v, err := strconv.ParseInt(s, 10, 0)
                if err == nil {
                        return v, nil
                }

the new tests fail until parseint is changed, then they all succeed