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)
|
||||
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