diff --git a/util/gutil/gutil_map.go b/util/gutil/gutil_map.go index e089281c1..89a5ad55c 100644 --- a/util/gutil/gutil_map.go +++ b/util/gutil/gutil_map.go @@ -1,4 +1,4 @@ -// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved. +// Copyright GoFrame Author(https://github.com/gogf/gf). All Rights Reserved. // // This Source Code Form is subject to the terms of the MIT License. // If a copy of the MIT was not distributed with this file, @@ -8,6 +8,7 @@ package gutil import ( "github.com/gogf/gf/internal/utils" + "reflect" ) // MapCopy does a shallow copy from map to for most commonly used map type @@ -103,3 +104,26 @@ func MapOmitEmpty(data map[string]interface{}) { } } } + +// MapToSlice converts map to slice of which all keys and values are its items. +// Eg: {"K1": "v1", "K2": "v2"} => ["K1", "v1", "K2", "v2"] +func MapToSlice(data interface{}) []interface{} { + var ( + reflectValue = reflect.ValueOf(data) + reflectKind = reflectValue.Kind() + ) + for reflectKind == reflect.Ptr { + reflectValue = reflectValue.Elem() + reflectKind = reflectValue.Kind() + } + switch reflectKind { + case reflect.Map: + array := make([]interface{}, 0) + for _, key := range reflectValue.MapKeys() { + array = append(array, key.Interface()) + array = append(array, reflectValue.MapIndex(key).Interface()) + } + return array + } + return nil +} diff --git a/util/gutil/gutil_struct.go b/util/gutil/gutil_struct.go new file mode 100644 index 000000000..f22ab9e57 --- /dev/null +++ b/util/gutil/gutil_struct.go @@ -0,0 +1,37 @@ +// Copyright GoFrame Author(https://github.com/gogf/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gutil + +import ( + "github.com/gogf/gf/util/gconv" + "reflect" +) + +// StructToSlice converts struct to slice of which all keys and values are its items. +// Eg: {"K1": "v1", "K2": "v2"} => ["K1", "v1", "K2", "v2"] +func StructToSlice(data interface{}) []interface{} { + var ( + reflectValue = reflect.ValueOf(data) + reflectKind = reflectValue.Kind() + ) + for reflectKind == reflect.Ptr { + reflectValue = reflectValue.Elem() + reflectKind = reflectValue.Kind() + } + switch reflectKind { + case reflect.Struct: + array := make([]interface{}, 0) + // Note that, it uses the gconv tag name instead of the attribute name if + // the gconv tag is fined in the struct attributes. + for k, v := range gconv.Map(reflectValue) { + array = append(array, k) + array = append(array, v) + } + return array + } + return nil +} diff --git a/util/gutil/gutil_z_unit_map_test.go b/util/gutil/gutil_z_unit_map_test.go index 9e2c79d13..07ede8454 100755 --- a/util/gutil/gutil_z_unit_map_test.go +++ b/util/gutil/gutil_z_unit_map_test.go @@ -1,4 +1,4 @@ -// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved. +// Copyright GoFrame Author(https://github.com/gogf/gf). All Rights Reserved. // // This Source Code Form is subject to the terms of the MIT License. // If a copy of the MIT was not distributed with this file, @@ -134,3 +134,39 @@ func Test_MapOmitEmpty(t *testing.T) { t.AssertNE(m["k2"], nil) }) } + +func Test_MapToSlice(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + m := g.Map{ + "k1": "v1", + "k2": "v2", + } + s := gutil.MapToSlice(m) + t.Assert(len(s), 4) + t.AssertIN(s[0], g.Slice{"k1", "k2", "v1", "v2"}) + t.AssertIN(s[1], g.Slice{"k1", "k2", "v1", "v2"}) + t.AssertIN(s[2], g.Slice{"k1", "k2", "v1", "v2"}) + t.AssertIN(s[3], g.Slice{"k1", "k2", "v1", "v2"}) + }) + gtest.C(t, func(t *gtest.T) { + m := g.MapStrStr{ + "k1": "v1", + "k2": "v2", + } + s := gutil.MapToSlice(m) + t.Assert(len(s), 4) + t.AssertIN(s[0], g.Slice{"k1", "k2", "v1", "v2"}) + t.AssertIN(s[1], g.Slice{"k1", "k2", "v1", "v2"}) + t.AssertIN(s[2], g.Slice{"k1", "k2", "v1", "v2"}) + t.AssertIN(s[3], g.Slice{"k1", "k2", "v1", "v2"}) + }) + gtest.C(t, func(t *gtest.T) { + m := g.MapStrStr{} + s := gutil.MapToSlice(m) + t.Assert(len(s), 0) + }) + gtest.C(t, func(t *gtest.T) { + s := gutil.MapToSlice(1) + t.Assert(s, nil) + }) +} diff --git a/util/gutil/gutil_z_unit_struct_test.go b/util/gutil/gutil_z_unit_struct_test.go new file mode 100755 index 000000000..a7e66be76 --- /dev/null +++ b/util/gutil/gutil_z_unit_struct_test.go @@ -0,0 +1,38 @@ +// Copyright GoFrame Author(https://github.com/gogf/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gutil_test + +import ( + "github.com/gogf/gf/frame/g" + "testing" + + "github.com/gogf/gf/test/gtest" + "github.com/gogf/gf/util/gutil" +) + +func Test_StructToSlice(t *testing.T) { + type A struct { + K1 int + K2 string + } + gtest.C(t, func(t *gtest.T) { + a := &A{ + K1: 1, + K2: "v2", + } + s := gutil.StructToSlice(a) + t.Assert(len(s), 4) + t.AssertIN(s[0], g.Slice{"K1", "K2", 1, "v2"}) + t.AssertIN(s[1], g.Slice{"K1", "K2", 1, "v2"}) + t.AssertIN(s[2], g.Slice{"K1", "K2", 1, "v2"}) + t.AssertIN(s[3], g.Slice{"K1", "K2", 1, "v2"}) + }) + gtest.C(t, func(t *gtest.T) { + s := gutil.StructToSlice(1) + t.Assert(s, nil) + }) +}