diff --git a/maputil/convert.go b/maputil/convert.go index eff3f3d87..5a351ffdd 100644 --- a/maputil/convert.go +++ b/maputil/convert.go @@ -33,6 +33,20 @@ func CombineToSMap(keys, values []string) SMap { return arrutil.CombineToSMap(keys, values) } +// ToAnyMap convert map[TYPE1]TYPE2 to map[string]any +func ToAnyMap(mp any) map[string]any { + rv := reflect.Indirect(reflect.ValueOf(mp)) + if rv.Kind() != reflect.Map { + panic("not a map value") + } + + anyMp := make(map[string]any, rv.Len()) + for _, key := range rv.MapKeys() { + anyMp[key.String()] = rv.MapIndex(key).Interface() + } + return anyMp +} + // HTTPQueryString convert map[string]any data to http query string. func HTTPQueryString(data map[string]any) string { ss := make([]string, 0, len(data)) diff --git a/maputil/convert_test.go b/maputil/convert_test.go index a425187b6..b5ecf70d1 100644 --- a/maputil/convert_test.go +++ b/maputil/convert_test.go @@ -31,6 +31,18 @@ func TestToStringMap(t *testing.T) { assert.Eq(t, "val0", mp.Str("key0")) } +func TestToAnyMap(t *testing.T) { + src := map[string]string{"a": "v0", "b": "23"} + + mp := maputil.ToAnyMap(src) + assert.Len(t, mp, 2) + assert.Eq(t, "v0", mp["a"]) + + assert.Panics(t, func() { + maputil.ToAnyMap(123) + }) +} + func TestHTTPQueryString(t *testing.T) { src := map[string]any{"a": "v0", "b": 23} str := maputil.HTTPQueryString(src) diff --git a/maputil/get.go b/maputil/get.go index 151d918cf..8c6c9c2db 100644 --- a/maputil/get.go +++ b/maputil/get.go @@ -101,14 +101,26 @@ func Keys(mp any) (keys []string) { // Values get all values from the given map. func Values(mp any) (values []any) { - rftVal := reflect.Indirect(reflect.ValueOf(mp)) - if rftVal.Kind() != reflect.Map { + rv := reflect.Indirect(reflect.ValueOf(mp)) + if rv.Kind() != reflect.Map { return } - values = make([]any, 0, rftVal.Len()) - for _, key := range rftVal.MapKeys() { - values = append(values, rftVal.MapIndex(key).Interface()) + values = make([]any, 0, rv.Len()) + for _, key := range rv.MapKeys() { + values = append(values, rv.MapIndex(key).Interface()) } return } + +// EachAnyMap iterates the given map and calls the given function for each item. +func EachAnyMap(mp any, fn func(key string, val any)) { + rv := reflect.Indirect(reflect.ValueOf(mp)) + if rv.Kind() != reflect.Map { + panic("not a map value") + } + + for _, key := range rv.MapKeys() { + fn(key.String(), rv.MapIndex(key).Interface()) + } +} diff --git a/maputil/get_test.go b/maputil/get_test.go index 0e79eaa22..f5551a495 100644 --- a/maputil/get_test.go +++ b/maputil/get_test.go @@ -126,3 +126,20 @@ func TestValues(t *testing.T) { assert.Len(t, ret, 0) } + +func TestEachAnyMap(t *testing.T) { + mp := map[string]any{ + "key0": "v0", + "key1": "v1", + "key2": 34, + } + + maputil.EachAnyMap(mp, func(k string, v any) { + assert.NotEmpty(t, k) + assert.NotEmpty(t, v) + }) + + assert.Panics(t, func() { + maputil.EachAnyMap(1, nil) + }) +}