feat: check variable is base type
This commit is contained in:
parent
9bee051e56
commit
a82af1d66c
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
.idea
|
8
builder.go
Normal file
8
builder.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package goref
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
|
func BuildSlice(t reflect.Type) any {
|
||||||
|
sliceT := reflect.SliceOf(t)
|
||||||
|
return reflect.MakeSlice(sliceT, 0, 0).Interface()
|
||||||
|
}
|
17
builder_test.go
Normal file
17
builder_test.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package goref_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitter.top/common/goref"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBuildSliceStruct(t *testing.T) {
|
||||||
|
type T struct {
|
||||||
|
A string
|
||||||
|
}
|
||||||
|
var a T
|
||||||
|
at := reflect.TypeOf(a)
|
||||||
|
value := goref.BuildSlice(at)
|
||||||
|
t.Log(value.([]T))
|
||||||
|
}
|
12
go.mod
12
go.mod
@ -1,3 +1,11 @@
|
|||||||
module gitter.top/coco/goref
|
module gitter.top/common/goref
|
||||||
|
|
||||||
go 1.20
|
go 1.21
|
||||||
|
|
||||||
|
require github.com/stretchr/testify v1.8.4
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
)
|
||||||
|
10
go.sum
Normal file
10
go.sum
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
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.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
27
keys.go
Normal file
27
keys.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package goref
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
|
func ExistMapKey(val any, key string) bool {
|
||||||
|
vo := reflect.ValueOf(val)
|
||||||
|
if vo.Kind() == reflect.Ptr {
|
||||||
|
vo = vo.Elem()
|
||||||
|
}
|
||||||
|
if vo.Kind() != reflect.Map {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
getter := vo.MapIndex(reflect.ValueOf(key))
|
||||||
|
return getter.IsValid()
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExistStructField(val any, field string) bool {
|
||||||
|
vo := reflect.ValueOf(val)
|
||||||
|
if vo.Kind() == reflect.Ptr {
|
||||||
|
vo = vo.Elem()
|
||||||
|
}
|
||||||
|
if vo.Kind() != reflect.Struct {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
getter := vo.FieldByName(field)
|
||||||
|
return getter.IsValid()
|
||||||
|
}
|
98
type.go
98
type.go
@ -139,3 +139,101 @@ func IsChannel(val any) bool {
|
|||||||
typeOf := reflect.TypeOf(val)
|
typeOf := reflect.TypeOf(val)
|
||||||
return typeOf.Kind() == reflect.Chan
|
return typeOf.Kind() == reflect.Chan
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsBaseStruct(val any) bool {
|
||||||
|
typeOf := reflect.TypeOf(val)
|
||||||
|
if typeOf.Kind() == reflect.Ptr {
|
||||||
|
typeOf = typeOf.Elem()
|
||||||
|
}
|
||||||
|
return typeOf.Kind() == reflect.Struct
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsBaseMap(val any) bool {
|
||||||
|
typeOf := reflect.TypeOf(val)
|
||||||
|
if typeOf.Kind() == reflect.Ptr {
|
||||||
|
typeOf = typeOf.Elem()
|
||||||
|
}
|
||||||
|
return typeOf.Kind() == reflect.Map
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsBaseString(val any) bool {
|
||||||
|
typeOf := reflect.TypeOf(val)
|
||||||
|
if typeOf.Kind() == reflect.Ptr {
|
||||||
|
typeOf = typeOf.Elem()
|
||||||
|
}
|
||||||
|
return typeOf.Kind() == reflect.String
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsBaseSlice(val any) bool {
|
||||||
|
typeOf := reflect.TypeOf(val)
|
||||||
|
if typeOf.Kind() == reflect.Ptr {
|
||||||
|
typeOf = typeOf.Elem()
|
||||||
|
}
|
||||||
|
return typeOf.Kind() == reflect.Slice
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsBaseArray(val any) bool {
|
||||||
|
typeOf := reflect.TypeOf(val)
|
||||||
|
if typeOf.Kind() == reflect.Ptr {
|
||||||
|
typeOf = typeOf.Elem()
|
||||||
|
}
|
||||||
|
return typeOf.Kind() == reflect.Array
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsBaseList(val any) bool {
|
||||||
|
return IsBaseSlice(val) || IsBaseArray(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetListBaseType(val any) reflect.Type {
|
||||||
|
to := reflect.TypeOf(val)
|
||||||
|
if to.Kind() == reflect.Ptr {
|
||||||
|
to = to.Elem()
|
||||||
|
}
|
||||||
|
if to.Kind() != reflect.Slice && to.Kind() != reflect.Array {
|
||||||
|
panic("invalid type: " + to.String())
|
||||||
|
}
|
||||||
|
to = to.Elem()
|
||||||
|
if to.Kind() == reflect.Ptr {
|
||||||
|
to = to.Elem()
|
||||||
|
}
|
||||||
|
return to
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMapValueBaseType(val any) reflect.Type {
|
||||||
|
to := reflect.TypeOf(val)
|
||||||
|
if to.Kind() == reflect.Ptr {
|
||||||
|
to = to.Elem()
|
||||||
|
}
|
||||||
|
if to.Kind() != reflect.Map {
|
||||||
|
panic("invalid type: " + to.String())
|
||||||
|
}
|
||||||
|
to = to.Elem()
|
||||||
|
if to.Kind() == reflect.Ptr {
|
||||||
|
to = to.Elem()
|
||||||
|
}
|
||||||
|
return to
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetBaseType(val any) reflect.Type {
|
||||||
|
to := reflect.TypeOf(val)
|
||||||
|
if to.Kind() == reflect.Ptr {
|
||||||
|
to = to.Elem()
|
||||||
|
}
|
||||||
|
if to.Kind() == reflect.Map || to.Kind() == reflect.Array || to.Kind() == reflect.Slice || to.Kind() == reflect.Chan {
|
||||||
|
to = to.Elem()
|
||||||
|
}
|
||||||
|
if to.Kind() == reflect.Ptr {
|
||||||
|
to = to.Elem()
|
||||||
|
}
|
||||||
|
return to
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsBasicType(val any) bool {
|
||||||
|
rt := GetBaseType(val)
|
||||||
|
switch rt.Kind() {
|
||||||
|
case reflect.Chan, reflect.Struct, reflect.Array, reflect.Func, reflect.Map, reflect.Slice, reflect.Interface:
|
||||||
|
return false
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
34
type_test.go
Normal file
34
type_test.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package goref_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"gitter.top/common/goref"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIsBaseStruct(t *testing.T) {
|
||||||
|
type T struct{}
|
||||||
|
var a T
|
||||||
|
t.Log(goref.IsBaseStruct(a))
|
||||||
|
var list any = []T{}
|
||||||
|
t.Log(reflect.TypeOf(list))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToInterfaces(t *testing.T) {
|
||||||
|
type T string
|
||||||
|
var list any = []T{
|
||||||
|
"hello",
|
||||||
|
"world",
|
||||||
|
}
|
||||||
|
t.Log(goref.ToInterfaces(list))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetBaseType(t *testing.T) {
|
||||||
|
var ch = make(chan int, 5)
|
||||||
|
assert.EqualValues(t, reflect.Int, goref.GetBaseType(ch).Kind())
|
||||||
|
var slice []string
|
||||||
|
assert.EqualValues(t, reflect.String, goref.GetBaseType(slice).Kind())
|
||||||
|
var m map[string]struct{}
|
||||||
|
assert.EqualValues(t, reflect.Struct, goref.GetBaseType(m).Kind())
|
||||||
|
}
|
160
value.go
Normal file
160
value.go
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
package goref
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ToString(val any) (string, bool) {
|
||||||
|
vo := reflect.ValueOf(val)
|
||||||
|
if vo.Kind() == reflect.Ptr {
|
||||||
|
vo = vo.Elem()
|
||||||
|
}
|
||||||
|
if vo.Kind() == reflect.String {
|
||||||
|
return vo.String(), true
|
||||||
|
}
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToStrings(val any) ([]string, bool) {
|
||||||
|
vo := reflect.ValueOf(val)
|
||||||
|
if vo.Kind() == reflect.Ptr {
|
||||||
|
vo = vo.Elem()
|
||||||
|
}
|
||||||
|
if vo.Kind() == reflect.Slice || vo.Kind() == reflect.Array {
|
||||||
|
var list []string
|
||||||
|
for i := 0; i < vo.Len(); i++ {
|
||||||
|
val := vo.Index(i).Interface()
|
||||||
|
valVo := reflect.ValueOf(val)
|
||||||
|
if valVo.Kind() == reflect.Ptr {
|
||||||
|
valVo = valVo.Elem()
|
||||||
|
}
|
||||||
|
if valVo.Kind() == reflect.String {
|
||||||
|
list = append(list, valVo.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list, true
|
||||||
|
}
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToInterfaces(val any) ([]interface{}, bool) {
|
||||||
|
vo := reflect.ValueOf(val)
|
||||||
|
if vo.Kind() == reflect.Ptr {
|
||||||
|
vo = vo.Elem()
|
||||||
|
}
|
||||||
|
if vo.Len() == 0 {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
var result []interface{}
|
||||||
|
for i := 0; i < vo.Len(); i++ {
|
||||||
|
result = append(result, vo.Index(i).Interface())
|
||||||
|
}
|
||||||
|
return result, true
|
||||||
|
}
|
||||||
|
|
||||||
|
type tagger struct {
|
||||||
|
tag string
|
||||||
|
omitempty bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tagger) merge() {
|
||||||
|
if t.tag == "" {
|
||||||
|
t.tag = "-"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type taggerOption func(*tagger)
|
||||||
|
|
||||||
|
func WithTag(tag string) taggerOption {
|
||||||
|
return func(tager *tagger) {
|
||||||
|
tager.tag = tag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithOmitempty(omit bool) taggerOption {
|
||||||
|
return func(tager *tagger) {
|
||||||
|
tager.omitempty = omit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func StructToMap(val any, tagOpts ...taggerOption) (map[string]interface{}, error) {
|
||||||
|
vo := reflect.ValueOf(val)
|
||||||
|
if vo.Kind() == reflect.Ptr {
|
||||||
|
vo = vo.Elem()
|
||||||
|
}
|
||||||
|
if vo.Kind() != reflect.Struct {
|
||||||
|
return nil, fmt.Errorf("val type not struct")
|
||||||
|
}
|
||||||
|
var data = make(map[string]interface{})
|
||||||
|
var tagger = new(tagger)
|
||||||
|
for _, opt := range tagOpts {
|
||||||
|
opt(tagger)
|
||||||
|
}
|
||||||
|
tagger.merge()
|
||||||
|
for i := 0; i < vo.NumField(); i++ {
|
||||||
|
vf := vo.Field(i)
|
||||||
|
if tagger.omitempty && vf.IsZero() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
key := vo.Type().Field(i).Tag.Get(tagger.tag)
|
||||||
|
if key == "" {
|
||||||
|
key = vo.Type().Field(i).Name
|
||||||
|
}
|
||||||
|
if strings.Contains(key, ",omitempty") {
|
||||||
|
key = strings.Replace(key, ",omitempty", "", 1)
|
||||||
|
}
|
||||||
|
data[key] = vf.Interface()
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SliceStructToMap slice struct to map, field as key
|
||||||
|
// value type []struct, bind type *map[string]*struct
|
||||||
|
func SliceStructToMap(value, bind any, field string) error {
|
||||||
|
// bind type check
|
||||||
|
if GetListBaseType(value) != GetMapValueBaseType(bind) {
|
||||||
|
return fmt.Errorf("struct type no match map type")
|
||||||
|
}
|
||||||
|
|
||||||
|
vo := reflect.ValueOf(value)
|
||||||
|
if vo.Kind() == reflect.Ptr {
|
||||||
|
vo = vo.Elem()
|
||||||
|
}
|
||||||
|
if vo.Kind() != reflect.Slice && vo.Kind() != reflect.Array {
|
||||||
|
return fmt.Errorf("val type not array or slice: " + vo.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
bo := reflect.ValueOf(bind)
|
||||||
|
if bo.Kind() == reflect.Ptr {
|
||||||
|
bo = bo.Elem()
|
||||||
|
}
|
||||||
|
if bo.Kind() != reflect.Map {
|
||||||
|
return fmt.Errorf("invalid map type")
|
||||||
|
}
|
||||||
|
if !bo.CanSet() {
|
||||||
|
return fmt.Errorf("bind map must be initialized")
|
||||||
|
}
|
||||||
|
boKey := bo.Type().Key()
|
||||||
|
boVal := bo.Type().Elem()
|
||||||
|
bo.Set(reflect.MakeMap(reflect.MapOf(boKey, boVal)))
|
||||||
|
|
||||||
|
for i := 0; i < vo.Len(); i++ {
|
||||||
|
t := vo.Index(i)
|
||||||
|
if t.Kind() == reflect.Ptr {
|
||||||
|
t = t.Elem()
|
||||||
|
}
|
||||||
|
idxField := t.FieldByName(field)
|
||||||
|
if idxField.Kind() == reflect.Invalid {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
idxVal := vo.Index(i)
|
||||||
|
if boVal.Kind() == reflect.Ptr {
|
||||||
|
bo.SetMapIndex(idxField, idxVal.Addr())
|
||||||
|
} else {
|
||||||
|
bo.SetMapIndex(idxField, idxVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
31
value_test.go
Normal file
31
value_test.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package goref_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"gitter.top/common/goref"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSliceStructToMap(t *testing.T) {
|
||||||
|
type T struct {
|
||||||
|
Id string
|
||||||
|
}
|
||||||
|
var a []T
|
||||||
|
a = append(a, T{
|
||||||
|
Id: "1",
|
||||||
|
})
|
||||||
|
a = append(a, T{
|
||||||
|
Id: "2",
|
||||||
|
})
|
||||||
|
a = append(a, T{
|
||||||
|
Id: "3",
|
||||||
|
})
|
||||||
|
a = append(a, T{
|
||||||
|
Id: "4",
|
||||||
|
})
|
||||||
|
|
||||||
|
var bind = make(map[string]T)
|
||||||
|
err := goref.SliceStructToMap(a, &bind, "Id")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
t.Logf("map: %#v", bind["1"])
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user