Skip to content

Commit

Permalink
improve indirect
Browse files Browse the repository at this point in the history
  • Loading branch information
shockerli committed Nov 16, 2021
1 parent 06f58ef commit 4ee9c78
Show file tree
Hide file tree
Showing 9 changed files with 35 additions and 33 deletions.
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ go get -u github.com/shockerli/cvt

## Usage

[中文说明](README_ZH.md)
English | [中文](README_ZH.md)

### with `error`

Expand Down Expand Up @@ -113,9 +113,8 @@ cvt.Float("hello", 12.34) // 12.34
### slice
- `ColumnsE`: the values from a single column in the input array/slice/map of struct/map, `[]interface{}`
- `FieldE`: the field value from map/struct, `interface{}`
- `KeysE`: the keys of map, `[]interface{}`
- `Slice`
- `SliceE`: convert an interface to a `[]interface{}` type
- `KeysE`: the keys of map, or fields of struct, `[]interface{}`
- `Slice` / `SliceE`: convert an interface to a `[]interface{}` type
- `SliceIntE`: convert an interface to a `[]int` type
- `SliceInt64E`: convert an interface to a `[]int64` type
- `SliceFloat64E`: convert an interface to a `[]float64` type
Expand Down
9 changes: 4 additions & 5 deletions README_ZH.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
[![codecov](https://codecov.io/gh/shockerli/cvt/branch/master/graph/badge.svg)](https://codecov.io/gh/shockerli/cvt)
![GitHub](https://img.shields.io/github/license/shockerli/cvt)

> 简单、安全的转换任意类型值,包括自定义类型
> 一个简单、安全、高效的转换任意数据类型的 Go 语言工具包,支持自定义类型、提取结构体字段和值
## 安装

Expand All @@ -17,7 +17,7 @@ go get -u github.com/shockerli/cvt

## 使用

[English](README.md)
中文 | [English](README.md)

### 支持 `error`

Expand Down Expand Up @@ -111,9 +111,8 @@ cvt.Float("hello", 12.34) // 12.34
### slice
- `ColumnsE`: 类似于 PHP 中的 `array_column``FieldE` 函数的切片版本,返回 `[]interface{}`
- `FieldE`: 取 `map``struct` 的字段值,返回 `interface{}`
- `KeysE`: 取 `map` 的键名,返回 `[]interface{}`
- `Slice`
- `SliceE`: 转换成 `[]interface{}`
- `KeysE`: 取 `map` 的键名,或结构体的字段名,返回 `[]interface{}`
- `Slice` / `SliceE`: 转换成 `[]interface{}`
- `SliceIntE`: 转换成 `[]int`
- `SliceInt64E`: 转换成 `[]int64`
- `SliceFloat64E`: 转换成 `[]float64`
Expand Down
4 changes: 2 additions & 2 deletions bool.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func Bool(v interface{}, def ...bool) bool {

// BoolE convert an interface to a bool type
func BoolE(val interface{}) (bool, error) {
v, rk, rv := indirect(val)
v, rv := indirect(val)

switch vv := v.(type) {
case bool:
Expand All @@ -40,7 +40,7 @@ func BoolE(val interface{}) (bool, error) {
return false, nil
}

switch rk.Kind() {
switch rv.Kind() {
// by elem length
case reflect.Array, reflect.Slice, reflect.Map:
return rv.Len() > 0, nil
Expand Down
15 changes: 7 additions & 8 deletions cvte.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ func FieldE(val interface{}, field interface{}) (interface{}, error) {
}

sf := String(field) // match with the String of field, so field can be any type
_, rt, rv := indirect(val)
_, rv := indirect(val)

switch rt.Kind() {
switch rv.Kind() {
case reflect.Map: // key of map
for _, key := range rv.MapKeys() {
if String(key.Interface()) == sf {
Expand All @@ -42,10 +42,10 @@ func FieldE(val interface{}, field interface{}) (interface{}, error) {
}

// return the values of struct fields, and deep find the embedded fields
func deepStructValues(rt reflect.Type, rv reflect.Value) (sl []interface{}) {
func deepStructValues(rv reflect.Value) (sl []interface{}) {
for j := 0; j < rv.NumField(); j++ {
if rt.Field(j).Anonymous {
sl = append(sl, deepStructValues(rt.Field(j).Type, rv.Field(j))...)
if rv.Type().Field(j).Anonymous {
sl = append(sl, deepStructValues(rv.Field(j))...)
} else if rv.Field(j).CanInterface() {
sl = append(sl, rv.Field(j).Interface())
}
Expand All @@ -63,16 +63,15 @@ func sortedMapKeys(v reflect.Value) (s []reflect.Value) {
}

// returns the value with base type
func indirect(a interface{}) (val interface{}, rt reflect.Type, rv reflect.Value) {
func indirect(a interface{}) (val interface{}, rv reflect.Value) {
if a == nil {
return
}

rt = reflect.TypeOf(a)
rv = reflect.ValueOf(a)
val = rv.Interface()

switch rt.Kind() {
switch rv.Kind() {
case reflect.Ptr: // indirect the base type, if is been referenced many times
for rv.Kind() == reflect.Ptr {
// stop indirect until nil, avoid stack overflow
Expand Down
2 changes: 1 addition & 1 deletion float.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func Float64(v interface{}, def ...float64) float64 {

// Float64E convert an interface to a float64 type
func Float64E(val interface{}) (float64, error) {
v, _, rv := indirect(val)
v, rv := indirect(val)

switch vv := v.(type) {
case nil:
Expand Down
4 changes: 2 additions & 2 deletions int.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ func convUint64(val interface{}) (uint64, error) {
}

// indirect type
v, _, rv := indirect(val)
v, rv := indirect(val)
switch vv := v.(type) {
case nil:
return 0, nil
Expand Down Expand Up @@ -423,7 +423,7 @@ func convInt64(val interface{}) (int64, error) {
}

// indirect type
v, _, rv := indirect(val)
v, rv := indirect(val)
switch vv := v.(type) {
case nil:
return 0, nil
Expand Down
23 changes: 14 additions & 9 deletions slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ func SliceE(val interface{}) (sl []interface{}, err error) {
return nil, errUnsupportedTypeNil
}

_, rt, rv := indirect(val)
_, rv := indirect(val)

switch rt.Kind() {
switch rv.Kind() {
case reflect.String:
for _, vvv := range rv.String() {
sl = append(sl, vvv)
Expand All @@ -43,7 +43,7 @@ func SliceE(val interface{}) (sl []interface{}, err error) {
}
return
case reflect.Struct:
sl = deepStructValues(rt, rv)
sl = deepStructValues(rv)
return
}

Expand Down Expand Up @@ -128,9 +128,9 @@ func ColumnsE(val interface{}, field interface{}) (sl []interface{}, err error)
return nil, errUnsupportedTypeNil
}

_, rt, rv := indirect(val)
_, rv := indirect(val)

switch rt.Kind() {
switch rv.Kind() {
case reflect.Slice, reflect.Array:
for j := 0; j < rv.Len(); j++ {
vv, e := FieldE(rv.Index(j).Interface(), field)
Expand All @@ -152,7 +152,7 @@ func ColumnsE(val interface{}, field interface{}) (sl []interface{}, err error)
return
}

return nil, fmt.Errorf("unsupported type: %s", rt.Name())
return nil, fmt.Errorf("unsupported type: %s", rv.Type().Name())
}

// KeysE return the keys of map, sorted by asc
Expand All @@ -161,15 +161,20 @@ func KeysE(val interface{}) (sl []interface{}, err error) {
return nil, errUnsupportedTypeNil
}

_, rt, rv := indirect(val)
_, rv := indirect(val)

switch rt.Kind() {
switch rv.Kind() {
case reflect.Map:
for _, key := range sortedMapKeys(rv) {
sl = append(sl, key.Interface())
}
return
// case reflect.Struct:
// for _, v := range deepStructFields(rv.Type()) {
// sl = append(sl, v)
// }
// return
}

return nil, fmt.Errorf("unsupported type: %s", rt.Name())
return nil, fmt.Errorf("unsupported type: %s", rv.Type().Name())
}
2 changes: 1 addition & 1 deletion string.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func StringE(val interface{}) (string, error) {
}

// indirect type
v, _, rv := indirect(val)
v, rv := indirect(val)
switch vv := v.(type) {
case nil:
return "", nil
Expand Down
2 changes: 1 addition & 1 deletion time.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func Time(v interface{}, def ...time.Time) time.Time {

// TimeE convert an interface to a time.Time type
func TimeE(val interface{}) (t time.Time, err error) {
v, _, _ := indirect(val)
v, _ := indirect(val)

// source type
switch vv := v.(type) {
Expand Down

0 comments on commit 4ee9c78

Please sign in to comment.