feat: check variable is base type

This commit is contained in:
xuthus5 2023-06-22 22:29:11 +08:00
parent 9bee051e56
commit a82af1d66c
Signed by: xuthus5
GPG Key ID: A23CF9620CBB55F9
10 changed files with 396 additions and 2 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.idea

8
builder.go Normal file
View 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
View 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
View File

@ -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
View 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
View 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
View File

@ -139,3 +139,101 @@ func IsChannel(val any) bool {
typeOf := reflect.TypeOf(val)
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
View 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
View 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
View 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"])
}