From 3849a6dd943af8ded45b36cbb5168c2512a470e8 Mon Sep 17 00:00:00 2001 From: Inhere Date: Wed, 24 May 2023 11:01:57 +0800 Subject: [PATCH] :sparkles: feat: reflects - add new util func IsSimpleKind(), SetRValue() --- reflects/check.go | 10 +++++++++- reflects/check_test.go | 21 +++++++++++++++++++++ reflects/conv.go | 6 +++++- reflects/util.go | 26 ++++++++++++++++++++++---- reflects/util_test.go | 5 +++++ 5 files changed, 62 insertions(+), 6 deletions(-) diff --git a/reflects/check.go b/reflects/check.go index 0045cf75c..acd256454 100644 --- a/reflects/check.go +++ b/reflects/check.go @@ -5,7 +5,7 @@ import ( "reflect" ) -// HasChild check. eg: array, slice, map, struct +// HasChild type check. eg: array, slice, map, struct func HasChild(v reflect.Value) bool { switch v.Kind() { case reflect.Array, reflect.Slice, reflect.Map, reflect.Struct: @@ -19,6 +19,14 @@ func IsArrayOrSlice(k reflect.Kind) bool { return k == reflect.Slice || k == reflect.Array } +// IsSimpleKind kind in: string, bool, intX, uintX, floatX +func IsSimpleKind(k reflect.Kind) bool { + if reflect.String == k { + return true + } + return k > reflect.Invalid && k <= reflect.Float64 +} + // IsAnyInt check is intX or uintX type func IsAnyInt(k reflect.Kind) bool { return k >= reflect.Int && k <= reflect.Uintptr diff --git a/reflects/check_test.go b/reflects/check_test.go index 764620f6f..85a9dca40 100644 --- a/reflects/check_test.go +++ b/reflects/check_test.go @@ -67,3 +67,24 @@ func TestIsEmptyValue(t *testing.T) { rv := reflect.ValueOf(T{}).Field(0) is.True(reflects.IsEmptyValue(rv)) } + +func TestIsSimpleKind(t *testing.T) { + testCases := []struct { + name string + input reflect.Kind + expected bool + }{ + {"invalid kind", reflect.Invalid, false}, + {"string kind", reflect.String, true}, + {"float64 kind", reflect.Float64, true}, + {"bool kind", reflect.Bool, true}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + if reflects.IsSimpleKind(tc.input) != tc.expected { + t.Errorf("expected %v but got %v", tc.expected, !tc.expected) + } + }) + } +} diff --git a/reflects/conv.go b/reflects/conv.go index ca4b34378..1dfa303a5 100644 --- a/reflects/conv.go +++ b/reflects/conv.go @@ -130,7 +130,11 @@ func ValueByKind(val any, kind reflect.Kind) (rv reflect.Value, err error) { return } -// ConvSlice make new type slice from old slice +// ConvSlice make new type slice from old slice, will auto convert element type. +// +// TIPs: +// +// Only support kind: string, bool, intX, uintX, floatX func ConvSlice(oldSlRv reflect.Value, newElemTyp reflect.Type) (rv reflect.Value, err error) { if !IsArrayOrSlice(oldSlRv.Kind()) { panic("only allow array or slice type value") diff --git a/reflects/util.go b/reflects/util.go index ae560c1b4..445c0e54b 100644 --- a/reflects/util.go +++ b/reflects/util.go @@ -50,12 +50,17 @@ func Len(v reflect.Value) int { return -1 } -// SliceSubKind get sub-elem kind of the array, slice, variadic-var. +// SliceSubKind get sub-elem kind of the array, slice, variadic-var. alias SliceElemKind() +func SliceSubKind(typ reflect.Type) reflect.Kind { + return SliceElemKind(typ) +} + +// SliceElemKind get sub-elem kind of the array, slice, variadic-var. // // Usage: // -// SliceSubKind(reflect.TypeOf([]string{"abc"})) // reflect.String -func SliceSubKind(typ reflect.Type) reflect.Kind { +// SliceElemKind(reflect.TypeOf([]string{"abc"})) // reflect.String +func SliceElemKind(typ reflect.Type) reflect.Kind { if typ.Kind() == reflect.Slice || typ.Kind() == reflect.Array { return typ.Elem().Kind() } @@ -91,7 +96,7 @@ func SetUnexportedValue(rv reflect.Value, value any) { reflect.NewAt(rv.Type(), unsafe.Pointer(rv.UnsafeAddr())).Elem().Set(reflect.ValueOf(value)) } -// SetValue to a reflect.Value +// SetValue to a `reflect.Value`. will auto convert type if needed. func SetValue(rv reflect.Value, val any) error { // get real type of the ptr value if rv.Kind() == reflect.Ptr { @@ -112,6 +117,19 @@ func SetValue(rv reflect.Value, val any) error { return err } +// SetRValue to a `reflect.Value`. will direct set value without convert type. +func SetRValue(rv, val reflect.Value) { + if rv.Kind() == reflect.Ptr { + if rv.IsNil() { + elemTyp := rv.Type().Elem() + rv.Set(reflect.New(elemTyp)) + } + rv = reflect.Indirect(rv) + } + + rv.Set(val) +} + // EachMap process any map data func EachMap(mp reflect.Value, fn func(key, val reflect.Value)) { if fn == nil { diff --git a/reflects/util_test.go b/reflects/util_test.go index 8bbabc00c..c8eac6948 100644 --- a/reflects/util_test.go +++ b/reflects/util_test.go @@ -179,6 +179,11 @@ func TestSetValue(t *testing.T) { rv := reflect.ValueOf("val") _ = reflects.SetValue(rv, "new val") }) + + // test for SetRValue() + rv = reflect.ValueOf(&iVal) + reflects.SetRValue(rv, reflect.ValueOf(456)) + assert.Eq(t, 456, iVal) } func TestSetValue_map(t *testing.T) {