Skip to content

bdlm/cast

Repository files navigation

cast

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.

Release Candidate 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.

CHANGELOG

Release GoDoc Build status Coverage status Go Report Card Github issues Github pull requests MIT

This project is inspired by spf13/cast

What is 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.

Why use 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.

Usage

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.

Examples

channels

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
func

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)(),
)
String
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)
Int
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)
Error checking

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)

Supported Conversions

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