safe and easy casting from one type to another in Go

Related tags

Miscellaneous 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
Issues
  • 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
  • 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
  • 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
  • add support to cast uint32 slices

    add support to cast uint32 slices

    What does this MR does?

    Create ToUint32SliceE and ToUint32Slice method to support uint32 slice casting;

    How to test?

    • Run the unit tests:
    go test -v  -run TestToUint32SliceE .
    
    • Test code:
    input := []interface{}{1.2, 3.2}
    v = ToUint32Slice(input)
    fmt.Println(v)
    
    opened by Pantani 2
  • add support to cast uint slices

    add support to cast uint slices

    What does this MR does?

    Create ToUintSliceE and ToUintSlice method to support uint slice casting;

    How to test?

    • Run the unit tests:
    go test -v  -run TestToUintSliceE .
    
    • Test code:
    input := []interface{}{1.2, 3.2}
    v = ToUintSlice(input)
    fmt.Println(v)
    
    opened by Pantani 2
  • Add support for string to int slice conversion

    Add support for string to int slice conversion

    This PR adds support for a string to int slice conversion. The supported format is a space separated list of ints encoded as a string.

    An use case for this new conversion can be found here.

    Signed-off-by: Fabio Falzoi [email protected]

    opened by pippolo84 1
  • Bug: Wrong conversion ToUint64

    Bug: Wrong conversion ToUint64

    ...
    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
    
    opened by tdrozdovsky 1
  • Return error result when transform digital type  (except int) to bool

    Return error result when transform digital type (except int) to bool

    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)
    	}
    }
    
    opened by tiyee 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
Type-safe Prometheus metrics builder library for golang

gotoprom A Prometheus metrics builder gotoprom offers an easy to use declarative API with type-safe labels for building and using Prometheus metrics.

Cabify 93 Jun 9, 2022
Generate type-safe Go converters by simply defining an interface

goverter a "type-safe Go converter" generator goverter is a tool for creating type-safe converters. All you have to do is create an interface and exec

Jannis Mattheis 125 Jun 28, 2022
Type-safe atomic values for Go

Type-safe atomic values for Go One issue with Go's sync/atomic package is that there is no guarantee from the type system that operations on an intege

Alec Thomas 17 Apr 8, 2022
IBus Engine for GoVarnam. An easy way to type Indian languages on GNU/Linux systems.

IBus Engine For GoVarnam An easy way to type Indian languages on GNU/Linux systems. goibus - golang implementation of libibus Thanks to sarim and haun

Varnamproject 10 Feb 10, 2022
Library to work with MimeHeaders and another mime types. Library support wildcards and parameters.

Mime header Motivation This library created to help people to parse media type data, like headers, and store and match it. The main features of the li

Anton Ohorodnyk 27 May 1, 2022
Yet another Go REPL that works nicely. Featured with line editing, code completion, and more.

gore Yet another Go REPL that works nicely. Featured with line editing, code completion, and more. (Screencast taken with cho45/KeyCast) Usage gore Af

Hironao OTSUBO 4.5k Jun 26, 2022
Toy program for benchmarking safe and unsafe ways of saving a file

save-a-file benchmarks the many strategies an editor could use to save a file. Example output on a SSD: ext4: $ ./save-a-file ~/tmp/foo 29.195µs per s

null 2 Sep 13, 2021
Lithia is an experimental functional programming language with an implicit but strong and dynamic type system.

Lithia is an experimental functional programming language with an implicit but strong and dynamic type system. Lithia is designed around a few core concepts in mind all language features contribute to.

Valentin Knabel 6 Jun 14, 2022
Start of a project that would let people stay informed about safe running spaces in their area.

SafeRun Start of a project that would let people stay informed about safe running spaces in their area. Too many people I'm friends with feel unsafe w

Ryan Dunning 0 Feb 11, 2022
Analyze the binary outputted by `go build` to get type information etc.

Analyze the binary outputted by go build to get type information etc.

Masaaki Goshima 15 May 20, 2022
A tool to generate Pulumi Package schemas from Go type definitions

MkSchema A tool to generate Pulumi Package schemas from Go type definitions. This tool translates annotated Go files into Pulumi component schema meta

Joe Duffy 2 Jun 5, 2022
Quickly clone an entire org/users repositories into one directory - Supports GitHub, GitLab, Bitbucket, and more

ghorg ghorg allows you to quickly clone all of an orgs, or users repos into a single directory. This can be useful in many situations including Search

Jay Gabriels 942 Jun 28, 2022
Squizit is a simple tool, that aim to help you get the grade you want, not the one you have learnt for.

Squizit is a simple tool, that aim to help you get the grade you want, not the one you have learnt for. Screenshots First, input PIN Then enjoy! Hoste

cyan 11 Mar 11, 2022
Go implementation Welford’s method for one-pass variance computation

Variance and standard deviation caluculation using variance's algorithm Table of Contents Introduction Installation Usage Contributing License Introdu

Axiom, Inc. 7 Jun 5, 2022
Run The World. Command aggregator output. Define many services watch them in one place.

Run The World. Command aggregator output. Define many services watch them in one place.

Pierrick Martin 1 Feb 2, 2022
K3ai Executor is the runner pod to execute the "one-click" pipelines

Welcome to K3ai Project K3ai is a lightweight tool to get an AI Infrastructure Stack up in minutes not days. NOTE on the K3ai origins Original K3ai Pr

k3ai 0 Nov 11, 2021
Create one endpoint with add user functionality

hubuc-task Create one endpoint with add user functionality

Sachin Chavan 0 Nov 13, 2021
Assemble multiple CODEOWNERS file into one

Codeowners Tool to generate a GitHub CODEOWNERS file from multiple CODEOWNERS files throughout the repo. This makes it easier to manage code ownership

Georg Molau 2 Apr 11, 2022
gonewire: one wire library that uses the w1 kernel module

gonewire one wire library that uses the w1 kernel module. current support: DS18(S)20

T.Goehlert 1 Jan 25, 2022