safe and easy casting from one type to another in Go

Related tags

Utilities cast
Overview

cast

GoDoc Build Status Go Report Card

Easy and safe casting from one type to another in Go

Don’t Panic! ... Cast

What is Cast?

Cast is a library to convert between different go types in a consistent and easy way.

Cast provides simple functions to easily convert a number to a string, an interface into a bool, etc. Cast does this intelligently when an obvious conversion is possible. It doesn’t make any attempts to guess what you meant, for example you can only convert a string to an int when it is a string representation of an int such as “8”. Cast was developed for use in Hugo, a website engine which uses YAML, TOML or JSON for meta data.

Why use Cast?

When working with dynamic data in Go you often need to cast or convert the data from one type into another. Cast goes beyond just using type assertion (though it uses that when possible) to provide a very straightforward and convenient library.

If you are working with interfaces to handle things like dynamic content you’ll need an easy way to convert an interface into a given type. This is the library for you.

If you are taking in data from YAML, TOML or JSON or other formats which lack full types, then Cast is the library for you.

Usage

Cast provides a handful of To_____ methods. These methods will always return the desired type. If input is provided that will not convert to that type, the 0 or nil value for that type will be returned.

Cast also provides identical methods To_____E. These return the same result as the To_____ methods, plus an additional error which tells you if it successfully converted. Using these methods you can tell the difference between when the input matched the zero value or when the conversion failed and the zero value was returned.

The following examples are merely a sample of what is available. Please review the code for a complete set.

Example ‘ToString’:

cast.ToString("mayonegg")         // "mayonegg"
cast.ToString(8)                  // "8"
cast.ToString(8.31)               // "8.31"
cast.ToString([]byte("one time")) // "one time"
cast.ToString(nil)                // ""

var foo interface{} = "one more time"
cast.ToString(foo)                // "one more time"

Example ‘ToInt’:

cast.ToInt(8)                  // 8
cast.ToInt(8.31)               // 8
cast.ToInt("8")                // 8
cast.ToInt(true)               // 1
cast.ToInt(false)              // 0

var eight interface{} = 8
cast.ToInt(eight)              // 8
cast.ToInt(nil)                // 0
Comments
  • Add support for maps defined as a json string

    Add support for maps defined as a json string

    • As a fix for https://github.com/spf13/viper/issues/451 , this PR adds support for casting map types from JSON strings. This allows viper to support binding environment variables for more types. This uses the stdlib's encoding/json package for unmarshalling the data and bubbles up unmarshalling errors to the caller.
    • Add test cases to all map casting methods to test this feature
    • Add test cases to TestToDurationSliceE in order to reach 100% total coverage for the lib
    opened by xvello 8
  • use errUnableToCast instead of fmt.Errorf

    use errUnableToCast instead of fmt.Errorf

    • [x] added benchmarks
    • [x] use predefined errUnableToCast instead of fmt.Errorf
    • [x] fixed golint

    before:

    go test -bench=.
    goos: darwin
    goarch: amd64
    pkg: github.com/yanmhlv/cast
    BenchmarkTooBool/valid_bool(true)-4         	200000000	         8.25 ns/op	       0 B/op	       0 allocs/op
    BenchmarkTooBool/valid_bool(1)-4            	200000000	         8.36 ns/op	       0 B/op	       0 allocs/op
    BenchmarkTooBool/invalid_bool("xxx")-4      	30000000	        45.1 ns/op	      48 B/op	       1 allocs/op
    BenchmarkTooBool/invalid_bool(1.0)-4        	 5000000	       302 ns/op	      96 B/op	       3 allocs/op
    PASS
    

    after:

    goos: darwin
    goarch: amd64
    pkg: github.com/yanmhlv/cast
    BenchmarkTooBool/valid_bool(true)-4         	200000000	         8.03 ns/op	       0 B/op	       0 allocs/op
    BenchmarkTooBool/valid_bool(1)-4            	200000000	         8.20 ns/op	       0 B/op	       0 allocs/op
    BenchmarkTooBool/invalid_bool("xxx")-4      	30000000	        44.8 ns/op	      48 B/op	       1 allocs/op
    BenchmarkTooBool/invalid_bool(1.0)-4        	20000000	        76.0 ns/op	     112 B/op	       2 allocs/op
    PASS
    
    opened by yanmhlv 7
  • add time.Time">

    add "yyyy-MM-dd HH:mm:ss" string format > time.Time

    I notice that the Hugo use this project to convert the string to time.Time. When I migrate to Hugo from Hexo (another static blog generator). The Hugo said :

    page.go:750: Failed to parse date '2016-03-06 15:28:01' in page xxxxx.md

    I hope you can merge this Pull request, so that those people who migrate to Hugo from Hexo are easy to use Hugo to generate the static blog.

    Thanks. ^_^

    opened by emacsist 7
  • Add ToTimeInDefaultLocation/E

    Add ToTimeInDefaultLocation/E

    Go's time parsing uses UTC when the format doesn't have a timezone, and has even weirder behavior when it has a zone name but no numeric offset. A caller to cast.ToTime cannot know if the returned time was explicitly in UTC or was set by default, so they cannot fix it. These new functions allow a user to supply a different timezone to default to, with nil using the local zone.

    This addresses spf13/hugo#1882 by allowing that code to use cast.ToTimeInDefaultLocation(raw, nil).

    A note on the implementation: It's not possible to use time.ParseInLocation because parsing with a format that has a named zone but no numeric offset (such as time.RC1123Z) returns a time with a 0 offset in that name iff that's not the current local timezone (!!). You can verify this by changing like 521 to use time.ParseInLocation(format.format, s, defaultLocation) and commenting out the manual override in the body of the if clause – tests will fail.

    I think the root cause is that the time pkg has two parsing functions: time.Parse and time.ParseInLocation, both of which use a private workhorse fn time.parse. That private fn takes two zones: a default and what's considered "local". I'm not sure, but I think in order to get the effect we want, we'd need to call that fn with our default and the current local zone. However, time.Parse uses default of UTC, whereas time.ParseInLocation uses the given zone for both default & local.

    opened by heewa 6
  • Adding ToStringMapStringSlice Method

    Adding ToStringMapStringSlice Method

    This should fix #15 and from my personal testing works. I did notice there is no test method for a ToStringMapString so I didn't add a test for ToStringMapStringSlice. Having a ToStringMapString test would have been nice to follow/modify for a TestToStringMapStringSlice function.

    opened by jackspirou 6
  • Fix multiple interface{} values to ToStringMapStringSliceE

    Fix multiple interface{} values to ToStringMapStringSliceE

    This fixes passing map[string]interface{} with the map containing multiple strings. Previously the result is a slice with an empty string in it.

    I discovered when using https://github.com/spf13/viper with the following:

    {
      "key": [
        "val1",
        "val2"
      ]
    }
    

    Viper resolved this to map[string]interface{} and the val key became []string{""}

    opened by akupila 5
  • Add bool case to ToStringE

    Add bool case to ToStringE

    Casting an interface{} of type bool to string was missing. So added with this PR.

    s,err := ToStringE(true)
    fmt.Printf("%q Err: %s",s,err)
    // Output: "true" Err:
    
    opened by SchumacherFM 5
  • 'cast.ToString()' conversion error

    'cast.ToString()' conversion error

    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
    
    opened by 1314liuwei 3
  • StringToDate: +more RFC3339 forms without TZ colon

    StringToDate: +more RFC3339 forms without TZ colon

    Adds a form to handle the common format strftime("%FT%T%z"), which omits the (optional) colon from the timezone. Also adds a matching T-omitted form.

    opened by raehik 3
  • Can 「cast.toString()」API Support User-defined String Type?

    Can 「cast.toString()」API Support User-defined String Type?

    https://github.com/spf13/cast/blob/2b0eb0f724e320b655240e331aef36d1175986c2/caste.go#L903 when i define a type as: type InstStatus string this cast.toString() API cannot work cause 「indirectToStringerOrErrorand」will not get the type's Elem with reflect package API, it will turn to default branch and the result is ""

    opened by FitzBogard 2
  • add support to cast int64 slices

    add support to cast int64 slices

    What does this MR does?

    Create ToInt64SliceE and ToInt64Slice method to support int64 slice casting;

    How to test?

    • Run the unit tests:
    go test -v  -run TestToInt64SliceE .
    
    • Test code:
    input := []interface{}{1.2, 3.2}
    v = ToInt64Slice(input)
    fmt.Println(v)
    
    opened by Pantani 2
  • Support cast defined type

    Support cast defined type

    // You can edit this code!
    // Click here and start typing.
    package main
    
    import (
    	"fmt"
    
    	"github.com/spf13/cast"
    )
    
    type Hoge = string
    type Fuga string
    
    func main() {
    	h := Hoge("hoge")
    	f := Fuga("fuga")
    	fmt.Println(h, f)
    	fmt.Println(cast.ToString(h), cast.ToString(f))
    }
    
    // output
    hoge fuga
    hoge 
    
    opened by atsushi-ishibashi 0
  • ToStringMapString is unable to cast map[string][]interface{} and error is omitted

    ToStringMapString is unable to cast map[string][]interface{} and error is omitted

    Here is my sample code. I tried to turn SampleReq into a map[string]string. However,map["array"] turns out to be empty. I checked the code and found ToStringE() is unable to handle a slice and the error is omitted in the call stack.

    package main
    
    import (
    	"bytes"
    	"encoding/json"
    	"fmt"
    	"github.com/spf13/cast"
    )
    
    type SampleReq struct {
    	SampleString string  `json:"string"`
    	IntArray     []int32 `json:"array"`
    }
    
    func main() {
    	req := &SampleReq{
    		SampleString: "string",
    		IntArray:     append(make([]int32, 0), 123),
    	}
    	reqStr, _ := json.Marshal(req)
    	d := json.NewDecoder(bytes.NewReader(reqStr))
    	d.UseNumber()
    	var mapResult map[string]interface{}
    	_ = d.Decode(&mapResult)
    	castResult := cast.ToStringMapString(mapResult)
    	fmt.Printf("before cast %+v, after cast:%+v", mapResult, castResult) // map["array"] is lost
    
    	// a temporary fix
    	b, _ := json.Marshal(mapResult["array"])
    	castResult["array"] = string(b)
    }
    
    opened by Battery233 0
  • Fix issue where ToUintE() fails to parse uint bigger than math.MaxInt64

    Fix issue where ToUintE() fails to parse uint bigger than math.MaxInt64

    This prevented me from using 0x9b199b1c002b4b00 as a cmd.Flags().Uint64 (which would return 0 as the value)

    ref https://github.com/spf13/cobra/issues/1791

    opened by blacktop 3
  • There are still many missing types, do we need to complete them?

    There are still many missing types, do we need to complete them?

    The basic types are interface{}, bool, byte, string, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, time.Time, time. Duration Corresponding slice type []interface{}, []bool, []byte, []string, []int, ......, []time.Duration The corresponding Map type map[string]interface{}, map[string]bool, map[string]byte, map[string]string, map[string]int, ......, map[ string]time. Map type of the corresponding slice type, map[string][]interface{}, map[string][]bool, map[string][]byte, map[string][]string, ......, map[ string][]time. The corresponding Map type slice type, []map[string]interface{}, ...... The corresponding slice type of Map type, []map[string][]interface{} OMG

    Probably shouldn't discuss super complex combinations like [][][]map[string]map[string]map[string]map[string]map[string]map[string][][]interface{}, but the first and second level combinations mentioned above are probably necessary

    opened by yveshield 0
Releases(v1.5.0)
Owner
Steve Francia
@golang product lead at @google • Author, Speaker, Developer • Creator of @gohugoio, Cobra, Viper & spf13-vim • former @docker & @mongodb
Steve Francia
🍕 Enjoy a slice! A utility library for dealing with slices and maps that focuses on type safety and performance.

?? github.com/elliotchance/pie Enjoy a slice! pie is a library of utility functions for common operations on slices and maps. Quick Start FAQ What are

Elliot Chance 1.2k Dec 4, 2022
Yet another semantic version incrementor and tagger for git

git-tag-inc Increments the version number and tags it. (You will need to push) Usage ./git-tag-inc [major] [minor] [release] [test] [uat] git-tag-in

Arran Ubels 6 Apr 30, 2022
Yet another StructTag, with some features liked cache and alias.

Yet another StructTag, with some features liked cache and alias.

Ryan Liu 2 Nov 1, 2021
a thread-safe concurrent map for go

concurrent map As explained here and here, the map type in Go doesn't support concurrent reads and writes. concurrent-map provides a high-performance

Or Hiltch 3.4k Dec 4, 2022
Lightweight, Simple, Quick, Thread-Safe Golang Stack Implementation

stack Lightweight, Simple, Quick, Thread-Safe Golang Stack Implementation Purpose Provide a fast, thread safe, and generic Golang Stack API with minim

Brendan Wilson 5 May 3, 2022
A simple thread-safe, fixed size LRU written in Go. Based on dominictarr's Hashlru Algorithm. 🔃

go-hashlru A simple thread-safe, fixed size LRU written in Go. Based on dominictarr's Hashlru Algorithm. ?? Uses map[interface{}]interface{} to allow

Saurabh Pujari 71 Dec 5, 2022
Utility to restrict which package is allowed to import another package.

go-import-rules Utility to restrict which package is allowed to import another package. This tool will read import-rules.yaml or import-rules.yml in t

PAYFAZZ 0 Jan 7, 2022
A thread-safe concurrent map for go

concurrent map Original repo didn't support go mod and no any tags,so I forkd this repo add go mod support and patch a tag on this repo. No any code c

Yusan Kurban 0 Dec 7, 2021
efaceconv - Code generation tool for high performance conversion from interface{} to immutable type without allocations.

efaceconv High performance conversion from interface{} to immutable types without additional allocations This is tool for go generate and common lib (

Ivan 50 May 14, 2022
Type-driven code generation for Go

What’s this? gen is a code-generation tool for Go. It’s intended to offer generics-like functionality on your types. Out of the box, it offers offers

Matt Sherman 1.4k Dec 1, 2022
Go library for HTTP content type negotiation

Content-Type support library for Go This library can be used to parse the value Content-Type header (if one is present) and select an acceptable media

Elviss Strazdins 42 Jul 10, 2022
Quickly query a Terraform provider's data type.

Terraform Query Quickly query a Terraform provider's data type. Such as a GitHub repository: ➜ ~ tfq github_repository full_name hashicorp/terraform |

Matt Canty 1 Oct 12, 2021
Optional type using Go 1.18 generics.

go.eth-p.dev/goptional Generic Optional (or Go Optional, if you prefer) goptional is a package that provides an implementation of an Optional[T] monad

Ethan P. 0 Apr 2, 2022
A protoc plugin that generates fieldmask paths as static type properties for proto messages

protoc-gen-fieldmask A protoc plugin that generates fieldmask paths as static ty

null 12 Nov 3, 2022
Di - A (very) WIP Go 1.18+ generic dependency injection package based on type reflection

di A (very) WIP Go 1.18+ generic dependency injection package based on type refl

Ringo Hoffmann 5 Apr 26, 2022
The one-stop shop for most common Go functions

Pandati The one stop shop for most common Go functions Table of contents Pandati The one stop shop for most common Go functions Table of contents Purp

Lukasz Raczylo 2 Mar 21, 2022
Go implementation Welford’s method for one-pass variance computation

Welford - Online method of calculating variance and standard deviation Go implementation Welford’s method for one-pass variance computation with D. H.

Axiom, Inc. 7 Jun 5, 2022
A fully Go userland with Linux bootloaders! u-root can create a one-binary root file system (initramfs) containing a busybox-like set of tools written in Go.

u-root Description u-root embodies four different projects. Go versions of many standard Linux tools, such as ls, cp, or shutdown. See cmds/core for m

null 2k Nov 27, 2022
📚 Clone all your repositories from GitHub with one command!

An utility to clone easily all your repositories from GitHub. The process is done concurrently so it is quite fast.

Eliaz Bobadilla 5 Apr 6, 2022