spf13 / cast Goto Github PK
View Code? Open in Web Editor NEWsafe and easy casting from one type to another in Go
License: MIT License
safe and easy casting from one type to another in Go
License: MIT License
I like your project a lot. Although I know this project is dedicated to cast variables from one data type to another, it would be nice to have some helper functions to simplify the checking of a variable's data type such as the following function:
func IsArray(v interface{}) bool {
rv := reflect.ValueOf(v)
return rv.Kind() == reflect.Array || rv.Kind() == reflect.Slice
}
eg:
a := "0100"
b := cast.ToInt(a)
fmt.Println(b)
the result is 64 but what i want is 100
This would be pretty nice building block for reflect type casting; something like:
cast.ToReflectValue(i interface{}, value reflect.Values) error
You clam your library to be "safe casting from one type to another in Go", but in the code there are no checks for overflow when casting integer types:
switch s := i.(type) {
case int:
return int16(s), nil // <-- this may overflow
case int64:
return int16(s), nil // <-- this may overflow
case int32:
return int16(s), nil
case int16:
return s, nil
case int8:
return int16(s), nil
case uint:
return int16(s), nil // <-- this may overflow
case uint64:
return int16(s), nil // <-- this may overflow
case uint32:
return int16(s), nil // <-- this may overflow
case uint16:
return int16(s), nil // <-- this may overflow
case uint8:
return int16(s), nil
case float64:
return int16(s), nil // <-- this may overflow
case float32:
return int16(s), nil // <-- this may overflow
Adding bounds check like this: https://play.golang.org/p/Jgu2NYg1qi3 would solve the issue.
Beautiful library, thank you!
Hi,
It's a bit confusing to use inline json for map but having to use space separated items for slices.
For consistency it would be great to also support inline JSON for list.
What do you think?
use cast.toTime(timeStr).Unix() will get +8 Hours Unix TIme,different with time.ParseInLocation.Unix(),
in Beijing Area.
How To Resolve?
Hey,
Is there any specific reason you didn't want to implement ToIntSlice
, ToBoolSlice
, etc...?
I'm gonna need those eventually, so, I can make a pull request if you'd like?
Hi,
is there any specific reason we dont support unsigned value conversion?
Playground: https://play.golang.org/p/5bbxzoB4jNw
package main
import (
"fmt"
"github.com/spf13/cast"
)
func main() {
b := []B{{Foo: "one"},{Foo: "two"}}
bees, err := cast.ToSliceE(b)
if err != nil {
panic(err)
}
fmt.Printf("bees: %+v\n", bees)
}
type B struct {
Foo string
}
panic: unable to cast []main.B{main.B{Foo:"one"}, main.B{Foo:"two"}} of type []main.B to []interface{}
goroutine 1 [running]:
main.main()
/tmp/sandbox460370487/prog.go:14 +0x157
Program exited: status 2.
Lines 81 to 99 in 8807572
there only assert type int
, no int8
, int16
, int32
, int64
, uint
...
could we add these type case?
”8.00“ can't ToIntE, maybe expect 8 ?
Probably related to #80
To make it easier to use Go1.13's errors.Is
and errors.As
, it'd be great if the To___E
functions wrap a common "cast error" so that transitive callers to these functions can determine if an error comes from casting.
A slightly-silly example usecase:
func main() {
val, err := maybeCast("not_an_int")
if errors.Is(err, cast.Err) {
fmt.Println("unable to cast!")
}
fmt.Println(val)
}
func maybeCast(myVal string) (int, error) {
if someCondition() {
return cast.ToIntE(myVal)
}
return fmt.Errorf("unrelated error")
}
If there's interest, I'd love to make a PR. :)
As title said, when you transform int16, int64 or other digital type (not int) to bool, return an error result.
func try() {
var i int64 = 1
fmt.Println(cast.ToBool(i)) // false
}
because cast only assert int type.
// ToBoolE casts an interface to a bool type.
func ToBoolE(i interface{}) (bool, error) {
i = indirect(i)
switch b := i.(type) {
case bool:
return b, nil
case nil:
return false, nil
case int:
if i.(int) != 0 {
return true, nil
}
return false, nil
case string:
return strconv.ParseBool(i.(string))
default:
return false, fmt.Errorf("unable to cast %#v of type %T to bool", i, i)
}
}
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 ❌
When I cast a string with prefixed 0 like "0123" with cast.ToInt("0123"), it results into 83 instead of the expected 123
Example code:
package main
import (
"fmt"
"github.com/spf13/cast"
)
func main() {
numb := "0123"
castedNumb := cast.ToInt(t)
fmt.Println(numb, castedNumb)
}
A strange error occurs when I use toString. The example code is as follows:
package main
import (
"fmt"
"github.com/spf13/cast"
)
type NewString string
func main() {
var test NewString
test = "this is a test string"
fmt.Println("original: ",test)
fmt.Println("use string() func: ",string(test))
fmt.Println("use cast.ToString() func: ",cast.ToString(test))
fmt.Println(cast.ToString(test)=="")
}
Output:
original: this is a test string
use string() func: this is a test string
use cast.ToString() func:
true
I would like to have a method for casting from i interface{}
to uuid.UUID
?
I was hoping that ToStringSlice
would support turning a slice of ints into a slice of strings. Am I wrong in that assumption?
The following fails:
nums := []int{1,2,3,4,5}
out := cast.ToStringSlice(nums)
// expected: []string{"1","2","3","4","5"}
// actual: []
If I use ToStringSliceE
I get the error:
unable to cast []int{1, 2, 3, 4, 5} of type []int to []string
Is there a cast method that does what I want that I'm not aware of?
Go's time/Time.String()
func uses a non-standard format (who's idea was that??), which cast
doesn't check for. We should add 2006-01-02 15:04:05.999999999 -0700 MST
to StringToDate()
.
Reported at https://discuss.gohugo.io/t/should-dateformat-be-able-to-round-trip-dates/5223
...
inValue = "18446744073709551615"
log.Printf("inValue = %v", inValue )
outValue := cast.ToUint64(inValue )
log.Printf("outValue = %v", outValue )
...
Result for v1.4.1:
INFO[2022-06-06T14:01:00+03:00] inValue = 18446744073709551615
INFO[2022-06-06T14:01:00+03:00] outValue = 18446744073709551615
Result for v1.5.0:
INFO[2022-06-06T14:01:00+03:00] inValue = 18446744073709551615
INFO[2022-06-06T14:01:00+03:00] outValue = 0
Hi guys, you need to add uint cast support.
Now I have an error :(
cast.ToInt64E(uint(42))
//Unable to Cast 0x2a to int64
on "04", parsed to 4,
but on "08", parsed to 0
using go 1.7
Could you please add
ToMapInt = map[string]int
ToMapInt64 = map[string]int64
Thank you!
I would like to have a ToStringMapStringSlice
method that would return a map[string][]string
type. I tend to have types like these in config files, maybe others do as well? Very helpful for YAML.
See 7c3adfb
Here's an example:
package main
import (
"fmt"
"github.com/spf13/cast"
)
type BusinessStatusEnum string
const (
BusinessStatusInactive BusinessStatus = "Inactive"
BusinessStatusInvited BusinessStatus = "Invited"
BusinessStatusActive BusinessStatus = "Active"
BusinessStatusBlocked BusinessStatus = "Blocked"
)
func main() {
fmt.Printf("message should be(%s), but cast returns (%s)\n", BusinessStatusInactive, cast.ToString(BusinessStatusInactive))
}
Running the above program outputs:
jeff_walter@martai:~/Desktop/mart.ai/src/github.com/martai/platform$ !g
go run blah.go
message should be(Inactive), but cast returns ()
I would expect it to print the associated string value, Inactive
in this case.
panic: 2> unable to parse date: 1600285405
Code for reproduction:
https://play.golang.org/p/yyxxFcFhQg1
package main
import (
"fmt"
cast "github.com/spf13/cast"
)
func main() {
val, err := cast.ToTimeE(1600285405)
if err != nil {
panic(fmt.Sprintf("1> %v", err))
}
fmt.Println(val)
val, err = cast.ToTimeE(fmt.Sprintf("%v", 1600285405))
fmt.Println(val)
if err != nil {
panic(fmt.Sprintf("2> %v", err))
}
}
Redirected from Hugo issue gohugoio/hugo#5340 .
2006-01-02T15:04:05-0700
is a valid RFC 3339 date which is not successfully parsed by cast. Obviously we shouldn't be expected to parse every single date format on the planet, or even all the various RFC 3339 formats. strftime
however can only output its timezone in ±hhmm
format, so the omitted colon form is relatively common.
It's a trivial change, so I may make an associated PR.
package main
import (
"fmt"
"github.com/spf13/cast"
)
func main() {
a := map[string]string{"hello": "123"}
r := cast.ToStringMapInt(a)
fmt.Printf("%T %#v\n", r, r)
r = cast.ToStringMapInt(&a)
fmt.Printf("%T %#v\n", r, r)
}
//OUTPUT:
//map[string]int map[string]int{"hello":123}
//map[string]int map[string]int{}
If ToStringMapInt
does indirect
as well, then the ToStringMapInt
method will have a friendlier result.
git clone https://github.com/spf13/cast && cd cast && go test .
go: downloading github.com/stretchr/testify v1.2.2
--- FAIL: TestToTimeWithTimezones (0.02s)
--- FAIL: TestToTimeWithTimezones/3;timeFormatType=1;Mon,_02_Jan_2006_15:04:05_MST (0.00s)
--- FAIL: TestToTimeWithTimezones/3;timeFormatType=1;Mon,_02_Jan_2006_15:04:05_MST/local_timezone_without_a_default_location (0.00s)
require.go:157:
Error Trace: cast_test.go:1428
cast_test.go:1358
Error: Not equal:
expected: "Fri, 01 Jan 2016 00:00:00 +0000"
actual : "Fri, 01 Jan 2016 01:00:00 +0000"
Diff:
--- Expected
+++ Actual
@@ -1 +1 @@
-Fri, 01 Jan 2016 00:00:00 +0000
+Fri, 01 Jan 2016 01:00:00 +0000
Test: TestToTimeWithTimezones/3;timeFormatType=1;Mon,_02_Jan_2006_15:04:05_MST/local_timezone_without_a_default_location
--- FAIL: TestToTimeWithTimezones/3;timeFormatType=1;Mon,_02_Jan_2006_15:04:05_MST/time_in_the_local_timezone_default_location_not_UTC (0.00s)
require.go:157:
Error Trace: cast_test.go:1428
cast_test.go:1411
Error: Not equal:
expected: "Fri, 01 Jan 2016 00:00:00 +0330"
actual : "Fri, 01 Jan 2016 01:00:00 +0330"
Diff:
--- Expected
+++ Actual
@@ -1 +1 @@
-Fri, 01 Jan 2016 00:00:00 +0330
+Fri, 01 Jan 2016 01:00:00 +0330
Test: TestToTimeWithTimezones/3;timeFormatType=1;Mon,_02_Jan_2006_15:04:05_MST/time_in_the_local_timezone_default_location_not_UTC
--- FAIL: TestToTimeWithTimezones/5;timeFormatType=1;02_Jan_06_15:04_MST (0.00s)
--- FAIL: TestToTimeWithTimezones/5;timeFormatType=1;02_Jan_06_15:04_MST/local_timezone_without_a_default_location (0.00s)
require.go:157:
Error Trace: cast_test.go:1428
cast_test.go:1358
Error: Not equal:
expected: "Fri, 01 Jan 2016 00:00:00 +0000"
actual : "Fri, 01 Jan 2016 01:00:00 +0000"
Diff:
--- Expected
+++ Actual
@@ -1 +1 @@
-Fri, 01 Jan 2016 00:00:00 +0000
+Fri, 01 Jan 2016 01:00:00 +0000
Test: TestToTimeWithTimezones/5;timeFormatType=1;02_Jan_06_15:04_MST/local_timezone_without_a_default_location
--- FAIL: TestToTimeWithTimezones/5;timeFormatType=1;02_Jan_06_15:04_MST/time_in_the_local_timezone_default_location_not_UTC (0.00s)
require.go:157:
Error Trace: cast_test.go:1428
cast_test.go:1411
Error: Not equal:
expected: "Fri, 01 Jan 2016 00:00:00 +0330"
actual : "Fri, 01 Jan 2016 01:00:00 +0330"
Diff:
--- Expected
+++ Actual
@@ -1 +1 @@
-Fri, 01 Jan 2016 00:00:00 +0330
+Fri, 01 Jan 2016 01:00:00 +0330
Test: TestToTimeWithTimezones/5;timeFormatType=1;02_Jan_06_15:04_MST/time_in_the_local_timezone_default_location_not_UTC
--- FAIL: TestToTimeWithTimezones/6;timeFormatType=1;Monday,_02-Jan-06_15:04:05_MST (0.00s)
--- FAIL: TestToTimeWithTimezones/6;timeFormatType=1;Monday,_02-Jan-06_15:04:05_MST/local_timezone_without_a_default_location (0.00s)
require.go:157:
Error Trace: cast_test.go:1428
cast_test.go:1358
Error: Not equal:
expected: "Fri, 01 Jan 2016 00:00:00 +0000"
actual : "Fri, 01 Jan 2016 01:00:00 +0000"
Diff:
--- Expected
+++ Actual
@@ -1 +1 @@
-Fri, 01 Jan 2016 00:00:00 +0000
+Fri, 01 Jan 2016 01:00:00 +0000
Test: TestToTimeWithTimezones/6;timeFormatType=1;Monday,_02-Jan-06_15:04:05_MST/local_timezone_without_a_default_location
--- FAIL: TestToTimeWithTimezones/6;timeFormatType=1;Monday,_02-Jan-06_15:04:05_MST/time_in_the_local_timezone_default_location_not_UTC (0.00s)
require.go:157:
Error Trace: cast_test.go:1428
cast_test.go:1411
Error: Not equal:
expected: "Fri, 01 Jan 2016 00:00:00 +0330"
actual : "Fri, 01 Jan 2016 01:00:00 +0330"
Diff:
--- Expected
+++ Actual
@@ -1 +1 @@
-Fri, 01 Jan 2016 00:00:00 +0330
+Fri, 01 Jan 2016 01:00:00 +0330
Test: TestToTimeWithTimezones/6;timeFormatType=1;Monday,_02-Jan-06_15:04:05_MST/time_in_the_local_timezone_default_location_not_UTC
--- FAIL: TestToTimeWithTimezones/12;timeFormatType=1;Mon_Jan__2_15:04:05_MST_2006 (0.00s)
--- FAIL: TestToTimeWithTimezones/12;timeFormatType=1;Mon_Jan__2_15:04:05_MST_2006/local_timezone_without_a_default_location (0.00s)
require.go:157:
Error Trace: cast_test.go:1428
cast_test.go:1358
Error: Not equal:
expected: "Fri, 01 Jan 2016 00:00:00 +0000"
actual : "Fri, 01 Jan 2016 01:00:00 +0000"
Diff:
--- Expected
+++ Actual
@@ -1 +1 @@
-Fri, 01 Jan 2016 00:00:00 +0000
+Fri, 01 Jan 2016 01:00:00 +0000
Test: TestToTimeWithTimezones/12;timeFormatType=1;Mon_Jan__2_15:04:05_MST_2006/local_timezone_without_a_default_location
--- FAIL: TestToTimeWithTimezones/12;timeFormatType=1;Mon_Jan__2_15:04:05_MST_2006/time_in_the_local_timezone_default_location_not_UTC (0.00s)
require.go:157:
Error Trace: cast_test.go:1428
cast_test.go:1411
Error: Not equal:
expected: "Fri, 01 Jan 2016 00:00:00 +0330"
actual : "Fri, 01 Jan 2016 01:00:00 +0330"
Diff:
--- Expected
+++ Actual
@@ -1 +1 @@
-Fri, 01 Jan 2016 00:00:00 +0330
+Fri, 01 Jan 2016 01:00:00 +0330
Test: TestToTimeWithTimezones/12;timeFormatType=1;Mon_Jan__2_15:04:05_MST_2006/time_in_the_local_timezone_default_location_not_UTC
FAIL
FAIL github.com/spf13/cast 0.261s
FAIL
When I tried to parse "2016-03-06 15:28:01 +0900", I got a wrong result.
code:
ToTimeE("2016-03-06 15:28:01 +0900")
result I get:
time.Date(2016, 3, 6, 15, 28, 1, 0, time.UTC)
result I want:
time.Date(2016, 3, 6, 6, 28, 1, 0, time.UTC)
a := []string{"01", "02", "03", "04", "05", "06", "07", "08", "09"}
for _, v := range a {
fmt.Println(cast.ToInt64(v))
}
// output 1 2 3 4 5 6 7 0 0
// bug 08 => 0 09 =>0
Start tagging releases, beginning with v1.0.0
. Cast is stable. We have 100% test coverage with no known defects.
As a library, tagging stable releases communicates stability to the user (both in the code base and the API). We should strive to be good citizens of the Go community and help foster a mature ecosystem.
The forthcoming Go dep tool will use SemVer (via Masterminds/semver). Dave Cheney argues two things: tagging releases is a prerequisite to a better ecosystem ("No version information, no tools, and the situation never improves"); and the tag should start with a "v". I care less about the "v", but I prefer to have it.
Tagging releases would also allow us to make larger changes. I'm specifically thinking about spf13/afero #89, which would probably necessitate a new major version.
If we agree that this is a good idea, we should extend it to the other spf13 libraries (afero, cobra, viper, etc). Cast is a tiny library, so I figure we can start here and work our way up.
https://play.golang.org/p/5kUZwo1uV9W
package main
import (
"fmt"
"github.com/spf13/cast"
)
func main() {
fmt.Printf("%#v\n", cast.ToIntSlice(nil))
fmt.Printf("%#v\n", cast.ToStringSlice(nil))
}
Output:
[]int{}
[]string(nil)
In first line an empty slice returned, while second line returns a nil slice.
The ToInt variants supports nil, so that error does not make much sense.
Hey,
thanks to cast
. I found this library through viper.
I use viper to read a JSON configuration.
It works great so far. Viper has various support functions to get pre casted values. See Getting Values From Viper.
Next to standard types like string
or bool
is has support for GetStringMapStringSlice (which falls back to this library here).
Now my configuration file looks like this:
{
"repositories": [
{
"name": "myvendor/package",
"url": "git@othervcs:myvendor/package.git"
}
],
"dir": "/var/foo",
"mirror": true,
...
}
The repositories
would be a []map[string]string
.
I need to do a few operations on this construct like "Is this repository is configured? If yes, is there a url?". To solve this question i do it like
func GetRepositoryURLOfPackage(n string) (*url.URL, error) {
repositories := viper.Get("repositories")
repositoriesSlice := repositories.([]interface{})
if (len(repositoriesSlice) == 0) {
return nil, errors.New("No repositories configured.")
}
for _, repoEntry := range repositoriesSlice {
repoEntryMap := repoEntry.(map[string]interface{})
if val, ok := repoEntryMap["name"]; !ok {
if val.(string) == n {
// TODO: Check if key "url" exists
return repoEntryMap["url"].(string)
}
}
}
return nil, fmt.Errorf("No repository url found for package %s", n)
}
It works. A better solution would be to implement a ToStringMapStringSlice
function.
Now the question: Do you see the need or does it make sense to implement a ToStringMapStringSlice
into cast and enable this in viper as well?
Or should i implement it in my code and leave it there as a custom impl.?
The reason i ask:
There are multiple other usecases where those data structures are not implemented by cast like GetIntMapStringSlice
, etc.
So it would be "never" complete.
ToString cannot cast int64
There was an error converting varchar data from Mysql to Int64
I have a value id=16607535815717977617:
id1 := cast.ToString(id) // -1839208257991573999
id2 := strconv.FormatUint(id, 10) // 16607535815717977617
which is an unexpected behavior.
It is already configure, but the repo owner must set the "switch".
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.