Now with Generics!
This project adheres to Semantic Versioning. You should expect package stability in Minor and Patch version releases
- Major: backwards incompatible package updates
- Minor: feature additions
- Patch: bug fixes, backward compatible model and function changes, etc.
Code is fairly settled and is in use in production systems. Backwards-compatibility will be mintained unless serious issues are discovered and consensus on a better solution is reached.
This project is inspired by spf13/cast
cast
is a library to convert between different data types in a straigntforward and predictable way.
cast
provides a generic function to easily convert both simple types (number to a string, interface ito a bool, etc.) and complex types (slice to map and vice versa, any to func() any, any to chan any, etc.). Cast does this intelligently when an obvious conversion is possible and logically when a conversion requires a predictable measureable process, such as casting a map to a slice or a bool to a channel. It doesn’t make any assumptions about how types should be converted but follows simple predictable rules.
For example you can only cast a string to an int when it is a string representation of a number, such "6.789"
. In a case like this, a reliable predictable rule converts that value to int(6)
by converting it to a float64
and calling math.Floor()
. The reason it does not round is because there is no integer that is almost 7
, but there is a 6
which can be contained within the original float64
.
cast
is meant to simplify consumption of untyped or poorly typed data by removing all the boilerplate you would otherwise write for each use-case. More about cast
.
The primary use-case for cast
is consuming untyped or poorly/loosly typed data, especially from unpredictable data sources. This can require a lot of repetitive boilerplate for validating and then typing incomming data (string representations of numbers is incredibly common and usually useless except for printing).
cast
goes beyond just using type assertion (though it uses that whenever possible) to provide a very straightforward and usable API. If you are working with interfaces to handle dynamic content or are taking in data from YAML, TOML or JSON or other formats which lack full types or reliable producers, cast
can be used to get the boilerplate out of your line of sight so you can just work on your code.
cast
provides To[T any](any) T
and ToE[T any](any) (T, error)
methods. These methods will always return the desired type T
. While To
will accept any
type, not all conversions are possible, supportable, or sensible, but several useful and unique conversions are available.
If input is provided that will not convert to a specified type, the 0 or nil value for that type will be returned. In order to differentiate between success and the nil
value, the ToE
method will return both the cast value and any errors that occurred during the conversion.
Some conversions accept flags for finer grained control. For example, you can specify a default value for impossible conversions or specify the size of the backing array when casting to a slice.
Casting to a channel will return a channel of the specified type with a buffer size of 1 containing the typed value.
intCh := cast.To[chan int]("10")
ten = <-intCh // <-10 (int)
var strCh chan string
strCh = cast.To[chan string](10)
str := <-strCh // <-"10" (string)
boolval := <-cast.To[chan bool](1) // <-true (bool) - I have no idea why you would do that :) but it works
Casting to function will return a function that returns the cast value. This requires using the cast.Func
custom type
var intFunc cast.Func[int]
intFunc = cast.To[cast.Func[int]]("10")
fmt.Printf("%#v (%T)\n", intFunc(), intFunc()) // 10 (int)
strFunc := cast.To[cast.Func[string]](10)
fmt.Printf("%#v (%T)\n", strFunc(), strFunc()) // "10" (string)
var boolFunc cast.Func[bool]
boolFunc = cast.To[cast.Func[bool]](1)
fmt.Printf(
"%#v (%T)\n", // true (bool) - why tho?
cast.To[cast.Func[bool]](1)(),
cast.To[cast.Func[bool]](1)(),
)
strVal := cast.To[string]("Hi!") // "Hi!" (string)
strVal := cast.To[string](8) // "8" (string)
strVal := cast.To[string](8.31) // "8.31" (string)
strVal := cast.To[string]([]byte("one time")) // "one time" (string)
strVal := cast.To[string](nil) // "" (string)
var foo interface{} = "one more time"
strVal := cast.To[string](foo) // "one more time" (string)
intVal := cast.To[int](8) // 8 (int)
intVal := cast.To[int](8.31) // 8 (int)
intVal := cast.To[int]("8") // 8 (int)
intVal := cast.To[int]("8.31") // 8 (int)
intVal := cast.To[int]("8.51") // 8 (int)
intVal := cast.To[int](true) // 1 (int)
intVal := cast.To[int](false) // 0 (int)
var eight interface{} = 8
intVal := cast.To[int](eight) // 8 (int)
intVal := cast.To[int](nil) // 0 (int)
To capture any conversion errors, use the ToE
method:
intVal := cast.To[int]("Hi!") // 0 (int)
intVal, err := cast.ToE[int]("Hi!") // 0, unable to cast "Hi!" of type string to int (int, error)
To | bool |
complex64 |
complex128 |
float32 |
float64 |
int |
int8 |
int16 |
int32 |
int64 |
uint |
uint8 |
uint16 |
uint32 |
uint64 |
string |
slice |
map |
func |
chan |
|
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
From | any |
y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | y |
bool |
y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | n | n | y | y | |
complex64 |
y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | n | n | y | y | |
complex128 |
y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | n | n | y | y | |
float32 |
y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | n | n | y | y | |
float64 |
y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | n | n | y | y | |
int |
y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | n | n | y | y | |
int8 |
y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | n | n | y | y | |
int16 |
y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | n | n | y | y | |
int32 |
y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | n | n | y | y | |
int64 |
y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | n | n | y | y | |
uint |
y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | n | n | y | y | |
uint8 |
y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | n | n | y | y | |
uint16 |
y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | n | n | y | y | |
uint32 |
y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | n | n | y | y | |
uint64 |
y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | n | n | y | y | |
string |
y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | y | n | n | y | y | |
slice |
n | n | n | n | n | n | n | n | n | n | n | n | n | n | n | y | y | n | y | y | |
map |
n | n | n | n | n | n | n | n | n | n | n | n | n | n | n | y | n | n | y | y | |
func |
n | n | n | n | n | n | n | n | n | n | n | n | n | n | n | y | n | n | n | n | |
chan |
n | n | n | n | n | n | n | n | n | n | n | n | n | n | n | y | n | n | n | n |