Compare commits

...

11 Commits

Author SHA1 Message Date
梁 致源
d23e8d28a6 更新 'go.mod' 2020-07-02 03:54:00 +00:00
梁 致源
3ab4c71a58 更新 'README.md' 2020-07-02 03:43:16 +00:00
K4rian
1ffadf5510 Fix uint, uint8, uint16, uint32 and uint64 conversion in ToStringE function. 2019-12-18 08:28:14 +01:00
Bjørn Erik Pedersen
c01685bb84 travis: Only check gofmt on Go 1.12 2019-05-31 11:32:28 +02:00
Bjørn Erik Pedersen
a924560ecf
travis: Add Go 1.12 2019-05-30 20:38:32 +02:00
Bjørn Erik Pedersen
8c9545af88 Fix Travis build 2018-10-25 00:59:28 +02:00
Bjørn Erik Pedersen
76b6d6c500
Add go.mod 2018-10-24 20:03:41 +02:00
Bjørn Erik Pedersen
97e58d71a3
Update Travis config 2018-10-24 20:02:32 +02:00
Theofanis Despoudis
4dd38b8b57 Add support for map of int64 and map of int 2018-10-24 20:00:14 +02:00
Ben Orchard
efb632f0f6 tests: +date tests for RFC3339 no TZ colon cases 2018-10-21 23:25:45 +02:00
Ben Orchard
8934aa3ddd 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.
2018-10-21 23:25:45 +02:00
8 changed files with 208 additions and 27 deletions

View File

@ -1,8 +1,10 @@
language: go
env:
- GO111MODULE=on
sudo: required
go:
- 1.7.5
- 1.8
- "1.11.x"
- "1.12.x"
- tip
os:
- linux

View File

@ -1,4 +1,4 @@
# A Self-Documenting Makefile: http://marmelab.com/blog/2016/02/29/auto-documented-makefile.html
GOVERSION := $(shell go version | cut -d ' ' -f 3 | cut -d '.' -f 2)
.PHONY: check fmt lint test test-race vet test-cover-html help
.DEFAULT_GOAL := help
@ -12,11 +12,13 @@ test-race: ## Run tests with race detector
go test -race ./...
fmt: ## Run gofmt linter
ifeq "$(GOVERSION)" "12"
@for d in `go list` ; do \
if [ "`gofmt -l -s $$GOPATH/src/$$d | tee /dev/stderr`" ]; then \
echo "^ improperly formatted go files" && echo && exit 1; \
fi \
done
endif
lint: ## Run golint linter
@for d in `go list` ; do \

View File

@ -4,35 +4,25 @@ cast
[![Build Status](https://api.travis-ci.org/spf13/cast.svg?branch=master)](https://travis-ci.org/spf13/cast)
[![Go Report Card](https://goreportcard.com/badge/github.com/spf13/cast)](https://goreportcard.com/report/github.com/spf13/cast)
Easy and safe casting from one type to another in Go
在Go中轻松安全地从一种类型转换为另一种类型
Dont Panic! ... Cast
## What is Cast?
Cast is a library to convert between different go types in a consistent and easy way.
Cast是一个库用于以一致且简单的方式在不同的go类型之间进行转换。
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 doesnt 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](http://hugo.spf13.com), a website engine which uses YAML, TOML or JSON
for meta data.
Cast提供简单的功能可轻松将数字转换为字符串进入布尔等接口。当明显转换是可能的。 它不会尝试猜测您的意思例如您只能在字符串为字符串时将其转换为int
int的表示形式例如“ 8”。 Cast的开发目的是用于[Hugo](http://hugo.spf13.com), 使用YAMLTOML或JSON的网站引擎用于元数据。
## 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.
在Go中使用动态数据时您通常需要强制转换或转换数据
从一种类型变成另一种类型。 强制转换不仅限于使用类型断言(尽管
它在可能的情况下使用它)来提供非常直接和方便的库。
If you are working with interfaces to handle things like dynamic content
youll 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.
如果您正在使用接口来处理诸如动态内容之类的内容您将需要一种简单的方法来将接口转换为给定类型。 这个是您的库。
如果您要从YAMLTOML或JSON或其他缺少格式的数据中获取数据完整类型那么Cast是适合您的库。
## Usage

12
cast.go
View File

@ -122,6 +122,18 @@ func ToStringMapBool(i interface{}) map[string]bool {
return v
}
// ToStringMapInt casts an interface to a map[string]int type.
func ToStringMapInt(i interface{}) map[string]int {
v, _ := ToStringMapIntE(i)
return v
}
// ToStringMapInt64 casts an interface to a map[string]int64 type.
func ToStringMapInt64(i interface{}) map[string]int64 {
v, _ := ToStringMapInt64E(i)
return v
}
// ToStringMap casts an interface to a map[string]interface{} type.
func ToStringMap(i interface{}) map[string]interface{} {
v, _ := ToStringMapE(i)

View File

@ -821,6 +821,83 @@ func TestToStringMapBoolE(t *testing.T) {
}
}
func TestToStringMapIntE(t *testing.T) {
tests := []struct {
input interface{}
expect map[string]int
iserr bool
}{
{map[interface{}]interface{}{"v1": 1, "v2": 222}, map[string]int{"v1": 1, "v2": 222}, false},
{map[string]interface{}{"v1": 342, "v2": 5141}, map[string]int{"v1": 342, "v2": 5141}, false},
{map[string]int{"v1": 33, "v2": 88}, map[string]int{"v1": 33, "v2": 88}, false},
{map[string]int32{"v1": int32(33), "v2": int32(88)}, map[string]int{"v1": 33, "v2": 88}, false},
{map[string]uint16{"v1": uint16(33), "v2": uint16(88)}, map[string]int{"v1": 33, "v2": 88}, false},
{map[string]float64{"v1": float64(8.22), "v2": float64(43.32)}, map[string]int{"v1": 8, "v2": 43}, false},
{`{"v1": 67, "v2": 56}`, map[string]int{"v1": 67, "v2": 56}, false},
// errors
{nil, nil, true},
{testing.T{}, nil, true},
{"", nil, true},
}
for i, test := range tests {
errmsg := fmt.Sprintf("i = %d", i) // assert helper message
v, err := ToStringMapIntE(test.input)
if test.iserr {
assert.Error(t, err, errmsg)
continue
}
assert.NoError(t, err, errmsg)
assert.Equal(t, test.expect, v, errmsg)
// Non-E test
v = ToStringMapInt(test.input)
assert.Equal(t, test.expect, v, errmsg)
}
}
func TestToStringMapInt64E(t *testing.T) {
tests := []struct {
input interface{}
expect map[string]int64
iserr bool
}{
{map[interface{}]interface{}{"v1": int32(8), "v2": int32(888)}, map[string]int64{"v1": int64(8), "v2": int64(888)}, false},
{map[string]interface{}{"v1": int64(45), "v2": int64(67)}, map[string]int64{"v1": 45, "v2": 67}, false},
{map[string]int64{"v1": 33, "v2": 88}, map[string]int64{"v1": 33, "v2": 88}, false},
{map[string]int{"v1": 33, "v2": 88}, map[string]int64{"v1": 33, "v2": 88}, false},
{map[string]int32{"v1": int32(33), "v2": int32(88)}, map[string]int64{"v1": 33, "v2": 88}, false},
{map[string]uint16{"v1": uint16(33), "v2": uint16(88)}, map[string]int64{"v1": 33, "v2": 88}, false},
{map[string]float64{"v1": float64(8.22), "v2": float64(43.32)}, map[string]int64{"v1": 8, "v2": 43}, false},
{`{"v1": 67, "v2": 56}`, map[string]int64{"v1": 67, "v2": 56}, false},
// errors
{nil, nil, true},
{testing.T{}, nil, true},
{"", nil, true},
}
for i, test := range tests {
errmsg := fmt.Sprintf("i = %d", i) // assert helper message
v, err := ToStringMapInt64E(test.input)
if test.iserr {
assert.Error(t, err, errmsg)
continue
}
assert.NoError(t, err, errmsg)
assert.Equal(t, test.expect, v, errmsg)
// Non-E test
v = ToStringMapInt64(test.input)
assert.Equal(t, test.expect, v, errmsg)
}
}
func TestToStringMapStringE(t *testing.T) {
var stringMapString = map[string]string{"key 1": "value 1", "key 2": "value 2", "key 3": "value 3"}
var stringMapInterface = map[string]interface{}{"key 1": "value 1", "key 2": "value 2", "key 3": "value 3"}
@ -1112,6 +1189,7 @@ func TestToTimeEE(t *testing.T) {
{"Tue, 10 Nov 2009 23:00:00 UTC", time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), false}, // RFC1123
{"Tue, 10 Nov 2009 23:00:00 +0000", time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), false}, // RFC1123Z
{"2009-11-10T23:00:00Z", time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), false}, // RFC3339
{"2018-10-21T23:21:29+0200", time.Date(2018, 10, 21, 21, 21, 29, 0, time.UTC), false}, // RFC3339 without timezone hh:mm colon
{"2009-11-10T23:00:00Z", time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), false}, // RFC3339Nano
{"11:00PM", time.Date(0, 1, 1, 23, 0, 0, 0, time.UTC), false}, // Kitchen
{"Nov 10 23:00:00", time.Date(0, 11, 10, 23, 0, 0, 0, time.UTC), false}, // Stamp
@ -1119,6 +1197,7 @@ func TestToTimeEE(t *testing.T) {
{"Nov 10 23:00:00.000000", time.Date(0, 11, 10, 23, 0, 0, 0, time.UTC), false}, // StampMicro
{"Nov 10 23:00:00.000000000", time.Date(0, 11, 10, 23, 0, 0, 0, time.UTC), false}, // StampNano
{"2016-03-06 15:28:01-00:00", time.Date(2016, 3, 6, 15, 28, 1, 0, time.UTC), false}, // RFC3339 without T
{"2016-03-06 15:28:01-0000", time.Date(2016, 3, 6, 15, 28, 1, 0, time.UTC), false}, // RFC3339 without T or timezone hh:mm colon
{"2016-03-06 15:28:01", time.Date(2016, 3, 6, 15, 28, 1, 0, time.UTC), false},
{"2016-03-06 15:28:01 -0000", time.Date(2016, 3, 6, 15, 28, 1, 0, time.UTC), false},
{"2016-03-06 15:28:01 -00:00", time.Date(2016, 3, 6, 15, 28, 1, 0, time.UTC), false},

View File

@ -819,15 +819,15 @@ func ToStringE(i interface{}) (string, error) {
case int8:
return strconv.FormatInt(int64(s), 10), nil
case uint:
return strconv.FormatInt(int64(s), 10), nil
return strconv.FormatUint(uint64(s), 10), nil
case uint64:
return strconv.FormatInt(int64(s), 10), nil
return strconv.FormatUint(uint64(s), 10), nil
case uint32:
return strconv.FormatInt(int64(s), 10), nil
return strconv.FormatUint(uint64(s), 10), nil
case uint16:
return strconv.FormatInt(int64(s), 10), nil
return strconv.FormatUint(uint64(s), 10), nil
case uint8:
return strconv.FormatInt(int64(s), 10), nil
return strconv.FormatUint(uint64(s), 10), nil
case []byte:
return string(s), nil
case template.HTML:
@ -990,6 +990,87 @@ func ToStringMapE(i interface{}) (map[string]interface{}, error) {
}
}
// ToStringMapIntE casts an interface to a map[string]int{} type.
func ToStringMapIntE(i interface{}) (map[string]int, error) {
var m = map[string]int{}
if i == nil {
return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int", i, i)
}
switch v := i.(type) {
case map[interface{}]interface{}:
for k, val := range v {
m[ToString(k)] = ToInt(val)
}
return m, nil
case map[string]interface{}:
for k, val := range v {
m[k] = ToInt(val)
}
return m, nil
case map[string]int:
return v, nil
case string:
err := jsonStringToObject(v, &m)
return m, err
}
if reflect.TypeOf(i).Kind() != reflect.Map {
return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int", i, i)
}
mVal := reflect.ValueOf(m)
v := reflect.ValueOf(i)
for _, keyVal := range v.MapKeys() {
val, err := ToIntE(v.MapIndex(keyVal).Interface())
if err != nil {
return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int", i, i)
}
mVal.SetMapIndex(keyVal, reflect.ValueOf(val))
}
return m, nil
}
// ToStringMapInt64E casts an interface to a map[string]int64{} type.
func ToStringMapInt64E(i interface{}) (map[string]int64, error) {
var m = map[string]int64{}
if i == nil {
return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int64", i, i)
}
switch v := i.(type) {
case map[interface{}]interface{}:
for k, val := range v {
m[ToString(k)] = ToInt64(val)
}
return m, nil
case map[string]interface{}:
for k, val := range v {
m[k] = ToInt64(val)
}
return m, nil
case map[string]int64:
return v, nil
case string:
err := jsonStringToObject(v, &m)
return m, err
}
if reflect.TypeOf(i).Kind() != reflect.Map {
return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int64", i, i)
}
mVal := reflect.ValueOf(m)
v := reflect.ValueOf(i)
for _, keyVal := range v.MapKeys() {
val, err := ToInt64E(v.MapIndex(keyVal).Interface())
if err != nil {
return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int64", i, i)
}
mVal.SetMapIndex(keyVal, reflect.ValueOf(val))
}
return m, nil
}
// ToSliceE casts an interface to a []interface{} type.
func ToSliceE(i interface{}) ([]interface{}, error) {
var s []interface{}
@ -1137,9 +1218,11 @@ func StringToDate(s string) (time.Time, error) {
"2006-01-02 15:04:05.999999999 -0700 MST", // Time.String()
"2006-01-02",
"02 Jan 2006",
"2006-01-02T15:04:05-0700", // RFC3339 without timezone hh:mm colon
"2006-01-02 15:04:05 -07:00",
"2006-01-02 15:04:05 -0700",
"2006-01-02 15:04:05Z07:00", // RFC3339 without T
"2006-01-02 15:04:05Z0700", // RFC3339 without T or timezone hh:mm colon
"2006-01-02 15:04:05",
time.Kitchen,
time.Stamp,

7
go.mod Normal file
View File

@ -0,0 +1,7 @@
module golib.gaore.com/GaoreGo/cast
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.2.2
)

6
go.sum Normal file
View File

@ -0,0 +1,6 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=