cast

package module
v2.0.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 22, 2024 License: MIT Imports: 9 Imported by: 0

README

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

Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	Error                    = errors.Errorf("unable to cast value")
	ErrorSignedToUnsigned    = errors.Wrap(Error, "cannot cast signed value to unsigned integer")
	ErrorStrUnableToCast     = "unable to cast %#.10v of type %T to %T"
	ErrorStrErrorCastingFunc = "error casting %T to %T during function generation"
)

Functions

func To

func To[TTo Types](v any, o ...Ops) TTo

To casts the value `v` to the given type, ignoring any errors.

Example (Float64)
v := cast.To[float64]("1.234")
fmt.Printf("%#v (%T)", v, v)
Output:

1.234 (float64)
Example (Int)
v := cast.To[int]("1")
fmt.Printf("%#v (%T)", v, v)
Output:

1 (int)
Example (String)
v := cast.To[string](1.234)
fmt.Printf("%#v (%T)", v, v)
Output:

"1.234" (string)

func ToE

func ToE[TTo Types](val any, o ...Ops) (panicTo TTo, panicErr error)

ToE casts the value `v` to the given type, returning any errors.

If the given type is a channel, a channel with a buffer of 1 is created and the cast value `v` is added to the the channel before it is returned.

If the given type is an array a slice is created. To create a slice with a backing array with a spcific size, set the LENGTH flag to the desired size as an integer: `slice, err := cast.ToE[[]int](v, Ops{LENGTH: 10})`. The value `v` is cast to the required type and appended to the returned slice.

If the given type is a map, a map is created with a zero-value key containing the cast value `v` which is then returned.

ops: optional, some flags may be passed to control type conversions, for example when creating a channel the the buffer size can be specified.

Example (Error)
v, e := cast.ToE[int]("H!")
fmt.Printf("%#v (%T), %v", v, v, e)
Output:

0 (int), unable to cast "H!" of type string to int
Example (Float64)
v, e := cast.ToE[float64]("1")
fmt.Printf("%#v (%T), %v", v, v, e)
Output:

1 (float64), <nil>
Example (Int)
v, e := cast.ToE[int]("1")
fmt.Printf("%#v (%T), %v", v, v, e)
Output:

1 (int), <nil>
Example (String)
v, e := cast.ToE[string](float64(1.0))
fmt.Printf("%#v (%T), %v", v, v, e)
Output:

"1" (string), <nil>

Types

type Flag added in v2.0.1

type Flag int
const (
	DEFAULT             Flag = iota // TTo,  default return value on error
	DUPLICATE_KEY_ERROR             // bool, error on duplicate map key
	LENGTH                          // int,  number of elements in result
	SIZE                            // int,  context specific
	UNIQUE_VALUES                   // bool, dedupe slice values
	JSON                            // bool, encode strings as JSON
)

type Func

type Func[TTo Types] func() TTo

type Ops

type Ops map[Flag]any

type Tbase

type Tbase interface {
	~int | ~int8 | ~int16 | ~int32 | ~int64 |
		~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
		~float32 | ~float64 |
		~complex64 | ~complex128 |
		~string | ~bool |
		any
}

type Tchan

type Tchan interface {
	~chan Tbase |
		~chan []int | ~chan []int8 | ~chan []int16 | ~chan []int32 | ~chan []int64 |
		~chan []uint | ~chan []uint8 | ~chan []uint16 | ~chan []uint32 | ~chan []uint64 | ~chan []uintptr |
		~chan []float32 | ~chan []float64 |
		~chan []complex64 | ~chan []complex128 |
		~chan []string | ~chan []bool |
		~chan []any | ~chan Func[Tbase]
}

type Tmap

type Tmap interface {
	~map[Tbase]Tbase |
		~map[Tbase][]int |
		~map[Tbase][]int8 |
		~map[Tbase][]int16 |
		~map[Tbase][]int32 |
		~map[Tbase][]int64 |
		~map[Tbase][]uint |
		~map[Tbase][]uint8 |
		~map[Tbase][]uint16 |
		~map[Tbase][]uint32 |
		~map[Tbase][]uint64 |
		~map[Tbase][]uintptr |
		~map[Tbase][]float32 |
		~map[Tbase][]float64 |
		~map[Tbase][]complex64 |
		~map[Tbase][]complex128 |
		~map[Tbase][]string |
		~map[Tbase][]bool |
		~map[Tbase][]any |
		~map[Tbase][]Func[Tbase]
}

type Tslice

type Tslice interface {
	~[]int | ~[]int8 | ~[]int16 | ~[]int32 | ~[]int64 |
		~[]uint | ~[]uint8 | ~[]uint16 | ~[]uint32 | ~[]uint64 | ~[]uintptr |
		~[]float32 | ~[]float64 |
		~[]complex64 | ~[]complex128 |
		~[]string | ~[]bool |
		~[]any
}

type Types

type Types interface {
	Tbase | Tslice | Tchan | Tmap | Func[Tbase]
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL